Cargo.lock 🔗
@@ -5365,6 +5365,7 @@ dependencies = [
"ordered-float",
"project",
"settings",
+ "shellexpand",
"smallvec",
"theme",
"util",
Mikayla Maki created
Added settings for common terminal configurations
Cargo.lock | 1
assets/settings/default.json | 50 ++++
crates/settings/src/settings.rs | 51 ++++
crates/terminal/Cargo.toml | 1
crates/terminal/src/connection.rs | 43 +++
crates/terminal/src/terminal.rs | 178 +++++++++------
crates/terminal/src/terminal_element.rs | 35 ++
crates/terminal/src/tests/terminal_test_context.rs | 12
crates/zed/src/settings_file.rs | 19 +
crates/zed/src/zed.rs | 7
10 files changed, 296 insertions(+), 101 deletions(-)
@@ -5365,6 +5365,7 @@ dependencies = [
"ordered-float",
"project",
"settings",
+ "shellexpand",
"smallvec",
"theme",
"util",
@@ -54,7 +54,7 @@
// "soft_wrap": "none",
// 2. Soft wrap lines that overflow the editor:
// "soft_wrap": "editor_width",
- // 2. Soft wrap lines at the preferred line length
+ // 3. Soft wrap lines at the preferred line length
// "soft_wrap": "preferred_line_length",
"soft_wrap": "none",
// The column at which to soft-wrap lines, for buffers where soft-wrap
@@ -65,6 +65,54 @@
"hard_tabs": false,
// How many columns a tab should occupy.
"tab_size": 4,
+ // 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).
+ // "shell": "system"
+ // 2. A program:
+ // "shell": {
+ // "program": "sh"
+ // }
+ // 3. A program with arguments:
+ // "shell": {
+ // "with_arguments": {
+ // "program": "/bin/bash",
+ // "arguments": ["--login"]
+ // }
+ // }
+ "shell": "system",
+ // What working directory to use when launching the terminal.
+ // May take 4 values:
+ // 1. Use the current file's project directory.
+ // "working_directory": "current_project_directory"
+ // 2. Use the first project in this workspace's directory
+ // "working_directory": "first_project_directory"
+ // 3. Always use this platform's home directory (if we can find it)
+ // "working_directory": "always_home"
+ // 4. 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 we can find it)
+ // "working_directory": {
+ // "always": {
+ // "directory": "~/zed/projects/"
+ // }
+ // }
+ //
+ //
+ "working_directory": "current_project_directory",
+ //Any key-value pairs added to this list will be added to the terminal's
+ //enviroment. Use `:` to seperate multiple values, not multiple list items
+ "env": [
+ //["KEY", "value1:value2"]
+ ]
+ //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"
+ //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"
+ },
// Different settings for specific languages.
"languages": {
"Plain Text": {
@@ -22,14 +22,16 @@ pub use keymap_file::{keymap_file_json_schema, KeymapFileContent};
pub struct Settings {
pub projects_online_by_default: bool,
pub buffer_font_family: FamilyId,
- pub buffer_font_size: f32,
pub default_buffer_font_size: f32,
+ pub buffer_font_size: f32,
pub hover_popover_enabled: bool,
pub show_completions_on_input: bool,
pub vim_mode: bool,
pub autosave: Autosave,
pub editor_defaults: EditorSettings,
pub editor_overrides: EditorSettings,
+ pub terminal_defaults: TerminalSettings,
+ pub terminal_overrides: TerminalSettings,
pub language_defaults: HashMap<Arc<str>, EditorSettings>,
pub language_overrides: HashMap<Arc<str>, EditorSettings>,
pub theme: Arc<Theme>,
@@ -73,6 +75,38 @@ pub enum Autosave {
OnWindowChange,
}
+#[derive(Clone, Debug, Default, Deserialize, JsonSchema)]
+pub struct TerminalSettings {
+ pub shell: Option<Shell>,
+ pub working_directory: Option<WorkingDirectory>,
+ pub font_size: Option<f32>,
+ pub font_family: Option<String>,
+ pub env: Option<Vec<(String, String)>>,
+}
+
+#[derive(Clone, Debug, Deserialize, PartialEq, Eq, JsonSchema)]
+#[serde(rename_all = "snake_case")]
+pub enum Shell {
+ System,
+ Program(String),
+ WithArguments { program: String, args: Vec<String> },
+}
+
+impl Default for Shell {
+ fn default() -> Self {
+ Shell::System
+ }
+}
+
+#[derive(Clone, Debug, Deserialize, PartialEq, Eq, JsonSchema)]
+#[serde(rename_all = "snake_case")]
+pub enum WorkingDirectory {
+ CurrentProjectDirectory,
+ FirstProjectDirectory,
+ AlwaysHome,
+ Always { directory: String },
+}
+
#[derive(Clone, Debug, Default, Deserialize, JsonSchema)]
pub struct SettingsFileContent {
#[serde(default)]
@@ -92,6 +126,8 @@ pub struct SettingsFileContent {
#[serde(flatten)]
pub editor: EditorSettings,
#[serde(default)]
+ pub terminal: TerminalSettings,
+ #[serde(default)]
#[serde(alias = "language_overrides")]
pub languages: HashMap<Arc<str>, EditorSettings>,
#[serde(default)]
@@ -133,8 +169,10 @@ impl Settings {
format_on_save: required(defaults.editor.format_on_save),
enable_language_server: required(defaults.editor.enable_language_server),
},
- language_defaults: defaults.languages,
editor_overrides: Default::default(),
+ terminal_defaults: Default::default(),
+ terminal_overrides: Default::default(),
+ language_defaults: defaults.languages,
language_overrides: Default::default(),
theme: themes.get(&defaults.theme.unwrap()).unwrap(),
}
@@ -171,7 +209,14 @@ impl Settings {
merge(&mut self.vim_mode, data.vim_mode);
merge(&mut self.autosave, data.autosave);
+ // Ensure terminal font is loaded, so we can request it in terminal_element layout
+ if let Some(terminal_font) = &data.terminal.font_family {
+ font_cache.load_family(&[terminal_font]).log_err();
+ }
+
self.editor_overrides = data.editor;
+ self.terminal_defaults.font_size = data.terminal.font_size;
+ self.terminal_overrides = data.terminal;
self.language_overrides = data.languages;
}
@@ -239,6 +284,8 @@ impl Settings {
enable_language_server: Some(true),
},
editor_overrides: Default::default(),
+ terminal_defaults: Default::default(),
+ terminal_overrides: Default::default(),
language_defaults: Default::default(),
language_overrides: Default::default(),
projects_online_by_default: true,
@@ -22,6 +22,7 @@ futures = "0.3"
ordered-float = "2.1.1"
itertools = "0.10"
dirs = "4.0.0"
+shellexpand = "2.1.0"
[dev-dependencies]
gpui = { path = "../gpui", features = ["test-support"] }
@@ -2,7 +2,7 @@ mod keymappings;
use alacritty_terminal::{
ansi::{ClearMode, Handler},
- config::{Config, PtyConfig},
+ config::{Config, Program, PtyConfig},
event::{Event as AlacTermEvent, Notify},
event_loop::{EventLoop, Msg, Notifier},
grid::Scroll,
@@ -12,7 +12,7 @@ use alacritty_terminal::{
Term,
};
use futures::{channel::mpsc::unbounded, StreamExt};
-use settings::Settings;
+use settings::{Settings, Shell};
use std::{collections::HashMap, path::PathBuf, sync::Arc};
use gpui::{keymap::Keystroke, ClipboardItem, CursorStyle, Entity, ModelContext};
@@ -46,16 +46,32 @@ pub struct TerminalConnection {
impl TerminalConnection {
pub fn new(
working_directory: Option<PathBuf>,
+ shell: Option<Shell>,
+ env_vars: Option<Vec<(String, String)>>,
initial_size: SizeInfo,
cx: &mut ModelContext<Self>,
) -> TerminalConnection {
- let pty_config = PtyConfig {
- shell: None, //Use the users default shell
- working_directory: working_directory.clone(),
- hold: false,
+ let pty_config = {
+ let shell = shell.and_then(|shell| match shell {
+ Shell::System => None,
+ Shell::Program(program) => Some(Program::Just(program)),
+ Shell::WithArguments { program, args } => Some(Program::WithArgs { program, args }),
+ });
+
+ PtyConfig {
+ shell,
+ working_directory: working_directory.clone(),
+ hold: false,
+ }
};
let mut env: HashMap<String, String> = HashMap::new();
+ if let Some(envs) = env_vars {
+ for (var, val) in envs {
+ env.insert(var, val);
+ }
+ }
+
//TODO: Properly set the current locale,
env.insert("LC_ALL".to_string(), "en_US.UTF-8".to_string());
@@ -75,7 +91,20 @@ impl TerminalConnection {
let term = Arc::new(FairMutex::new(term));
//Setup the pty...
- let pty = tty::new(&pty_config, &initial_size, None).expect("Could not create tty");
+ let pty = {
+ if let Some(pty) = tty::new(&pty_config, &initial_size, None).ok() {
+ pty
+ } else {
+ let pty_config = PtyConfig {
+ shell: None,
+ working_directory: working_directory.clone(),
+ ..Default::default()
+ };
+
+ tty::new(&pty_config, &initial_size, None)
+ .expect("Failed with default shell too :(")
+ }
+ };
//And connect them together
let event_loop = EventLoop::new(
@@ -18,10 +18,10 @@ use gpui::{
};
use modal::deploy_modal;
-use project::{Project, ProjectPath};
-use settings::Settings;
+use project::{LocalWorktree, Project, ProjectPath};
+use settings::{Settings, WorkingDirectory};
use smallvec::SmallVec;
-use std::path::PathBuf;
+use std::path::{Path, PathBuf};
use workspace::{Item, Workspace};
use crate::terminal_element::TerminalEl;
@@ -110,8 +110,15 @@ impl Terminal {
false,
);
- let connection =
- cx.add_model(|cx| TerminalConnection::new(working_directory, size_info, cx));
+ let (shell, envs) = {
+ let settings = cx.global::<Settings>();
+ let shell = settings.terminal_overrides.shell.clone();
+ let envs = settings.terminal_overrides.env.clone(); //Should be short and cheap.
+ (shell, envs)
+ };
+
+ let connection = cx
+ .add_model(|cx| TerminalConnection::new(working_directory, shell, envs, size_info, cx));
Terminal::from_connection(connection, modal, cx)
}
@@ -371,12 +378,41 @@ impl Item for Terminal {
}
}
+///Get's the working directory for the given workspace, respecting the user's settings.
+fn get_wd_for_workspace(workspace: &Workspace, cx: &AppContext) -> Option<PathBuf> {
+ let wd_setting = cx
+ .global::<Settings>()
+ .terminal_overrides
+ .working_directory
+ .clone()
+ .unwrap_or(WorkingDirectory::CurrentProjectDirectory);
+ let res = match wd_setting {
+ WorkingDirectory::CurrentProjectDirectory => current_project_directory(workspace, cx),
+ WorkingDirectory::FirstProjectDirectory => first_project_directory(workspace, cx),
+ WorkingDirectory::AlwaysHome => None,
+ WorkingDirectory::Always { directory } => shellexpand::full(&directory)
+ .ok()
+ .map(|dir| Path::new(&dir.to_string()).to_path_buf())
+ .filter(|dir| dir.is_dir()),
+ };
+ res.or_else(|| home_dir())
+}
+
+///Get's the first project's home directory, or the home directory
+fn first_project_directory(workspace: &Workspace, cx: &AppContext) -> Option<PathBuf> {
+ workspace
+ .worktrees(cx)
+ .next()
+ .and_then(|worktree_handle| worktree_handle.read(cx).as_local())
+ .and_then(get_path_from_wt)
+}
+
///Gets the intuitively correct working directory from the given workspace
///If there is an active entry for this project, returns that entry's worktree root.
///If there's no active entry but there is a worktree, returns that worktrees root.
///If either of these roots are files, or if there are any other query failures,
/// returns the user's home directory
-fn get_wd_for_workspace(workspace: &Workspace, cx: &AppContext) -> Option<PathBuf> {
+fn current_project_directory(workspace: &Workspace, cx: &AppContext) -> Option<PathBuf> {
let project = workspace.project().read(cx);
project
@@ -384,12 +420,13 @@ fn get_wd_for_workspace(workspace: &Workspace, cx: &AppContext) -> Option<PathBu
.and_then(|entry_id| project.worktree_for_entry(entry_id, cx))
.or_else(|| workspace.worktrees(cx).next())
.and_then(|worktree_handle| worktree_handle.read(cx).as_local())
- .and_then(|wt| {
- wt.root_entry()
- .filter(|re| re.is_dir())
- .map(|_| wt.abs_path().to_path_buf())
- })
- .or_else(|| home_dir())
+ .and_then(get_path_from_wt)
+}
+
+fn get_path_from_wt(wt: &LocalWorktree) -> Option<PathBuf> {
+ wt.root_entry()
+ .filter(|re| re.is_dir())
+ .map(|_| wt.abs_path().to_path_buf())
}
#[cfg(test)]
@@ -398,10 +435,6 @@ mod tests {
use crate::tests::terminal_test_context::TerminalTestContext;
use super::*;
- use alacritty_terminal::{
- index::{Column, Line, Point, Side},
- selection::{Selection, SelectionType},
- };
use gpui::TestAppContext;
use std::path::Path;
@@ -419,37 +452,6 @@ mod tests {
.await;
}
- /// TODO: I don't think this is actually testing anything anymore.
- ///Integration test for selections, clipboard, and terminal execution
- #[gpui::test(retries = 5)]
- async fn test_copy(cx: &mut TestAppContext) {
-
- let mut cx = TerminalTestContext::new(cx);
- let grid_content = cx
- .execute_and_wait("expr 3 + 4", |content, _cx| content.contains("7"))
- .await;
-
- //Get the position of the result
- let idx = grid_content.chars().position(|c| c == '7').unwrap();
- let result_line = grid_content
- .chars()
- .take(idx)
- .filter(|c| *c == '\n')
- .count() as i32;
-
- let copy_res = cx.update_connection(|connection, _cx| {
- let mut term = connection.term.lock();
- term.selection = Some(Selection::new(
- SelectionType::Semantic,
- Point::new(Line(result_line), Column(0)),
- Side::Right,
- ));
- term.selection_to_string()
- });
-
- assert_eq!(copy_res.unwrap(), "7");
- }
-
///Working directory calculation tests
///No Worktrees in project -> home_dir()
@@ -469,8 +471,10 @@ mod tests {
assert!(active_entry.is_none());
assert!(workspace.worktrees(cx).next().is_none());
- let res = get_wd_for_workspace(workspace, cx);
- assert_eq!(res, home_dir())
+ let res = current_project_directory(workspace, cx);
+ assert_eq!(res, None);
+ let res = first_project_directory(workspace, cx);
+ assert_eq!(res, None);
});
}
@@ -507,8 +511,10 @@ mod tests {
assert!(active_entry.is_none());
assert!(workspace.worktrees(cx).next().is_some());
- let res = get_wd_for_workspace(workspace, cx);
- assert_eq!(res, home_dir())
+ let res = current_project_directory(workspace, cx);
+ assert_eq!(res, None);
+ let res = first_project_directory(workspace, cx);
+ assert_eq!(res, None);
});
}
@@ -543,7 +549,9 @@ mod tests {
assert!(active_entry.is_none());
assert!(workspace.worktrees(cx).next().is_some());
- let res = get_wd_for_workspace(workspace, cx);
+ let res = current_project_directory(workspace, cx);
+ assert_eq!(res, Some((Path::new("/root/")).to_path_buf()));
+ let res = first_project_directory(workspace, cx);
assert_eq!(res, Some((Path::new("/root/")).to_path_buf()));
});
}
@@ -555,17 +563,32 @@ mod tests {
let params = cx.update(AppState::test);
let project = Project::test(params.fs.clone(), [], cx).await;
let (_, workspace) = cx.add_window(|cx| Workspace::new(project.clone(), cx));
- let (wt, _) = project
+ let (wt1, _) = project
.update(cx, |project, cx| {
- project.find_or_create_local_worktree("/root.txt", true, cx)
+ project.find_or_create_local_worktree("/root1/", true, cx)
+ })
+ .await
+ .unwrap();
+
+ let (wt2, _) = project
+ .update(cx, |project, cx| {
+ project.find_or_create_local_worktree("/root2.txt", true, cx)
})
.await
.unwrap();
//Setup root
- let entry = cx
+ let _ = cx
.update(|cx| {
- wt.update(cx, |wt, cx| {
+ wt1.update(cx, |wt, cx| {
+ wt.as_local().unwrap().create_entry(Path::new(""), true, cx)
+ })
+ })
+ .await
+ .unwrap();
+ let entry2 = cx
+ .update(|cx| {
+ wt2.update(cx, |wt, cx| {
wt.as_local()
.unwrap()
.create_entry(Path::new(""), false, cx)
@@ -576,8 +599,8 @@ mod tests {
cx.update(|cx| {
let p = ProjectPath {
- worktree_id: wt.read(cx).id(),
- path: entry.path,
+ worktree_id: wt2.read(cx).id(),
+ path: entry2.path,
};
project.update(cx, |project, cx| project.set_active_path(Some(p), cx));
});
@@ -589,8 +612,10 @@ mod tests {
assert!(active_entry.is_some());
- let res = get_wd_for_workspace(workspace, cx);
- assert_eq!(res, home_dir());
+ let res = current_project_directory(workspace, cx);
+ assert_eq!(res, None);
+ let res = first_project_directory(workspace, cx);
+ assert_eq!(res, Some((Path::new("/root1/")).to_path_buf()));
});
}
@@ -601,17 +626,32 @@ mod tests {
let params = cx.update(AppState::test);
let project = Project::test(params.fs.clone(), [], cx).await;
let (_, workspace) = cx.add_window(|cx| Workspace::new(project.clone(), cx));
- let (wt, _) = project
+ let (wt1, _) = project
.update(cx, |project, cx| {
- project.find_or_create_local_worktree("/root/", true, cx)
+ project.find_or_create_local_worktree("/root1/", true, cx)
+ })
+ .await
+ .unwrap();
+
+ let (wt2, _) = project
+ .update(cx, |project, cx| {
+ project.find_or_create_local_worktree("/root2/", true, cx)
})
.await
.unwrap();
//Setup root
- let entry = cx
+ let _ = cx
.update(|cx| {
- wt.update(cx, |wt, cx| {
+ wt1.update(cx, |wt, cx| {
+ wt.as_local().unwrap().create_entry(Path::new(""), true, cx)
+ })
+ })
+ .await
+ .unwrap();
+ let entry2 = cx
+ .update(|cx| {
+ wt2.update(cx, |wt, cx| {
wt.as_local().unwrap().create_entry(Path::new(""), true, cx)
})
})
@@ -620,8 +660,8 @@ mod tests {
cx.update(|cx| {
let p = ProjectPath {
- worktree_id: wt.read(cx).id(),
- path: entry.path,
+ worktree_id: wt2.read(cx).id(),
+ path: entry2.path,
};
project.update(cx, |project, cx| project.set_active_path(Some(p), cx));
});
@@ -633,8 +673,10 @@ mod tests {
assert!(active_entry.is_some());
- let res = get_wd_for_workspace(workspace, cx);
- assert_eq!(res, Some((Path::new("/root/")).to_path_buf()));
+ let res = current_project_directory(workspace, cx);
+ assert_eq!(res, Some((Path::new("/root2/")).to_path_buf()));
+ let res = first_project_directory(workspace, cx);
+ assert_eq!(res, Some((Path::new("/root1/")).to_path_buf()));
});
}
}
@@ -27,6 +27,7 @@ use itertools::Itertools;
use ordered_float::OrderedFloat;
use settings::Settings;
use theme::TerminalStyle;
+use util::ResultExt;
use std::{cmp::min, ops::Range, rc::Rc, sync::Arc};
use std::{fmt::Debug, ops::Sub};
@@ -256,10 +257,11 @@ impl Element for TerminalEl {
for layout_line in &layout.layout_lines {
for layout_cell in &layout_line.cells {
let position = vec2f(
- origin.x() + layout_cell.point.column as f32 * layout.em_width.0,
+ (origin.x() + layout_cell.point.column as f32 * layout.em_width.0)
+ .floor(),
origin.y() + layout_cell.point.line as f32 * layout.line_height.0,
);
- let size = vec2f(layout.em_width.0, layout.line_height.0);
+ let size = vec2f(layout.em_width.0.ceil(), layout.line_height.0);
cx.scene.push_quad(Quad {
bounds: RectF::new(position, size),
@@ -318,7 +320,7 @@ impl Element for TerminalEl {
//Don't actually know the start_x for a line, until here:
let cell_origin = vec2f(
- origin.x() + point.column as f32 * layout.em_width.0,
+ (origin.x() + point.column as f32 * layout.em_width.0).floor(),
origin.y() + point.line as f32 * layout.line_height.0,
);
@@ -420,14 +422,33 @@ pub fn mouse_to_cell_data(
///Configures a text style from the current settings.
fn make_text_style(font_cache: &FontCache, settings: &Settings) -> TextStyle {
+ // Pull the font family from settings properly overriding
+ let family_id = settings
+ .terminal_overrides
+ .font_family
+ .as_ref()
+ .and_then(|family_name| font_cache.load_family(&[family_name]).log_err())
+ .or_else(|| {
+ settings
+ .terminal_defaults
+ .font_family
+ .as_ref()
+ .and_then(|family_name| font_cache.load_family(&[family_name]).log_err())
+ })
+ .unwrap_or(settings.buffer_font_family);
+
TextStyle {
color: settings.theme.editor.text_color,
- font_family_id: settings.buffer_font_family,
- font_family_name: font_cache.family_name(settings.buffer_font_family).unwrap(),
+ font_family_id: family_id,
+ font_family_name: font_cache.family_name(family_id).unwrap(),
font_id: font_cache
- .select_font(settings.buffer_font_family, &Default::default())
+ .select_font(family_id, &Default::default())
.unwrap(),
- font_size: settings.buffer_font_size,
+ font_size: settings
+ .terminal_overrides
+ .font_size
+ .or(settings.terminal_defaults.font_size)
+ .unwrap_or(settings.buffer_font_size),
font_properties: Default::default(),
underline: Default::default(),
}
@@ -1,7 +1,7 @@
use std::time::Duration;
use alacritty_terminal::term::SizeInfo;
-use gpui::{AppContext, ModelContext, ModelHandle, ReadModelWith, TestAppContext};
+use gpui::{AppContext, ModelHandle, ReadModelWith, TestAppContext};
use itertools::Itertools;
use crate::{
@@ -28,7 +28,8 @@ impl<'a> TerminalTestContext<'a> {
false,
);
- let connection = cx.add_model(|cx| TerminalConnection::new(None, size_info, cx));
+ let connection =
+ cx.add_model(|cx| TerminalConnection::new(None, None, None, size_info, cx));
TerminalTestContext { cx, connection }
}
@@ -56,13 +57,6 @@ impl<'a> TerminalTestContext<'a> {
})
}
- pub fn update_connection<F, S>(&mut self, f: F) -> S
- where
- F: FnOnce(&mut TerminalConnection, &mut ModelContext<TerminalConnection>) -> S,
- {
- self.connection.update(self.cx, |conn, cx| f(conn, cx))
- }
-
fn grid_as_str(connection: &TerminalConnection) -> String {
let term = connection.term.lock();
let grid_iterator = term.renderable_content().display_iter;
@@ -39,15 +39,20 @@ where
Self(rx)
}
+ ///Loads the given watched JSON file. In the special case that the file is
+ ///empty (ignoring whitespace) or is not a file, this will return T::default()
async fn load(fs: Arc<dyn Fs>, path: &Path) -> Option<T> {
- if fs.is_file(&path).await {
- fs.load(&path)
- .await
- .log_err()
- .and_then(|data| parse_json_with_comments(&data).log_err())
- } else {
- Some(T::default())
+ if !fs.is_file(&path).await {
+ return Some(T::default());
}
+
+ fs.load(&path).await.log_err().and_then(|data| {
+ if data.trim().is_empty() {
+ Some(T::default())
+ } else {
+ parse_json_with_comments(&data).log_err()
+ }
+ })
}
}
@@ -79,18 +79,25 @@ pub fn init(app_state: &Arc<AppState>, cx: &mut gpui::MutableAppContext) {
cx.add_global_action(move |_: &IncreaseBufferFontSize, cx| {
cx.update_global::<Settings, _, _>(|settings, cx| {
settings.buffer_font_size = (settings.buffer_font_size + 1.0).max(MIN_FONT_SIZE);
+ if let Some(terminal_font_size) = settings.terminal_overrides.font_size.as_mut() {
+ *terminal_font_size = (*terminal_font_size + 1.0).max(MIN_FONT_SIZE);
+ }
cx.refresh_windows();
});
});
cx.add_global_action(move |_: &DecreaseBufferFontSize, cx| {
cx.update_global::<Settings, _, _>(|settings, cx| {
settings.buffer_font_size = (settings.buffer_font_size - 1.0).max(MIN_FONT_SIZE);
+ if let Some(terminal_font_size) = settings.terminal_overrides.font_size.as_mut() {
+ *terminal_font_size = (*terminal_font_size - 1.0).max(MIN_FONT_SIZE);
+ }
cx.refresh_windows();
});
});
cx.add_global_action(move |_: &ResetBufferFontSize, cx| {
cx.update_global::<Settings, _, _>(|settings, cx| {
settings.buffer_font_size = settings.default_buffer_font_size;
+ settings.terminal_overrides.font_size = settings.terminal_defaults.font_size;
cx.refresh_windows();
});
});