ZIm/crates/terminal/src/terminal_settings.rs
Hans 4af542567c
Fix a spelling typo (#7059)
Release notes: N/A
2024-01-30 11:40:33 +02:00

266 lines
8.5 KiB
Rust

use gpui::{px, AbsoluteLength, AppContext, FontFeatures, Pixels};
use schemars::{
gen::SchemaGenerator,
schema::{InstanceType, RootSchema, Schema, SchemaObject},
JsonSchema,
};
use serde_derive::{Deserialize, Serialize};
use serde_json::Value;
use settings::SettingsJsonSchemaParams;
use std::{collections::HashMap, path::PathBuf};
#[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,
pub font_size: Option<Pixels>,
pub font_family: Option<String>,
pub line_height: TerminalLineHeight,
pub font_features: Option<FontFeatures>,
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: Pixels,
pub default_height: Pixels,
pub detect_venv: VenvSettings,
}
#[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum VenvSettings {
#[default]
Off,
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.
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,
Nushell,
}
#[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema)]
pub struct TerminalSettingsContent {
/// What shell to use when opening a terminal.
///
/// Default: system
pub shell: Option<Shell>,
/// What working directory to use when launching the terminal
///
/// Default: current_project_directory
pub working_directory: Option<WorkingDirectory>,
/// Sets the terminal's font size.
///
/// If this option is not included,
/// the terminal will default to matching the buffer's font size.
pub font_size: Option<f32>,
/// Sets the terminal's font family.
///
/// If this option is not included,
/// the terminal will default to matching the buffer's font family.
pub font_family: Option<String>,
/// Sets the terminal's line height.
///
/// Default: comfortable
pub line_height: Option<TerminalLineHeight>,
pub font_features: Option<FontFeatures>,
/// Any key-value pairs added to this list will be added to the terminal's
/// environment. Use `:` to separate multiple values.
///
/// Default: {}
pub env: Option<HashMap<String, String>>,
/// Sets the cursor blinking behavior in the terminal.
///
/// Default: terminal_controlled
pub blinking: Option<TerminalBlink>,
/// Sets whether Alternate Scroll mode (code: ?1007) is active by default.
/// Alternate Scroll mode converts mouse scroll events into up / down key
/// presses when in the alternate screen (e.g. when running applications
/// like vim or less). The terminal can still set and unset this mode.
///
/// Default: off
pub alternate_scroll: Option<AlternateScroll>,
/// Sets whether the option key behaves as the meta key.
///
/// Default: false
pub option_as_meta: Option<bool>,
/// Whether or not selecting text in the terminal will automatically
/// copy to the system clipboard.
///
/// Default: false
pub copy_on_select: Option<bool>,
pub dock: Option<TerminalDockPosition>,
/// Default width when the terminal is docked to the left or right.
///
/// Default: 640
pub default_width: Option<f32>,
/// Default height when the terminal is docked to the bottom.
///
/// Default: 320
pub default_height: Option<f32>,
/// Activates 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.
///
/// Default: on
pub detect_venv: Option<VenvSettings>,
}
impl settings::Settings for TerminalSettings {
const KEY: Option<&'static str> = Some("terminal");
type FileContent = TerminalSettingsContent;
fn load(
default_value: &Self::FileContent,
user_values: &[&Self::FileContent],
_: &mut AppContext,
) -> anyhow::Result<Self> {
Self::load_via_json_merge(default_value, user_values)
}
fn json_schema(
generator: &mut SchemaGenerator,
params: &SettingsJsonSchemaParams,
_: &AppContext,
) -> RootSchema {
let mut root_schema = generator.root_schema_for::<Self::FileContent>();
let available_fonts = params
.font_names
.iter()
.cloned()
.map(Value::String)
.collect();
let fonts_schema = SchemaObject {
instance_type: Some(InstanceType::String.into()),
enum_values: Some(available_fonts),
..Default::default()
};
root_schema
.definitions
.extend([("FontFamilies".into(), fonts_schema.into())]);
root_schema
.schema
.object
.as_mut()
.unwrap()
.properties
.extend([(
"font_family".to_owned(),
Schema::new_ref("#/definitions/FontFamilies".into()),
)]);
root_schema
}
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema, Default)]
#[serde(rename_all = "snake_case")]
pub enum TerminalLineHeight {
/// Use a line height that's comfortable for reading, 1.618
#[default]
Comfortable,
/// Use a standard line height, 1.3. This option is useful for TUIs,
/// particularly if they use box characters
Standard,
/// Use a custom line height.
Custom(f32),
}
impl TerminalLineHeight {
pub fn value(&self) -> AbsoluteLength {
let value = match self {
TerminalLineHeight::Comfortable => 1.618,
TerminalLineHeight::Standard => 1.3,
TerminalLineHeight::Custom(line_height) => f32::max(*line_height, 1.),
};
px(value).into()
}
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum TerminalBlink {
/// Never blink the cursor, ignoring the terminal mode.
Off,
/// Default the cursor blink to off, but allow the terminal to
/// set blinking.
TerminalControlled,
/// Always blink the cursor, ignoring the terminal mode.
On,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum Shell {
/// Use the system's default terminal configuration in /etc/passwd
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 {
/// Use the current file's project directory. Will Fallback to the
/// first project directory strategy if unsuccessful.
CurrentProjectDirectory,
/// Use the first project in this workspace's directory.
FirstProjectDirectory,
/// Always use this platform's home directory (if it can be found).
AlwaysHome,
/// Always use a specific directory. This value will be shell expanded.
/// If this path is not a valid directory the terminal will default to
/// this platform's home directory (if it can be found).
Always { directory: String },
}