ElyMark: the writing view reaches the document - width, font, size, focus, typewriter (C14.12)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
b459cea4a2
commit
cb228769a7
7 files changed
+132
-6
No files matched your search
@@ -105,6 +105,7 @@ impl Host for Desk {
|
||||
/// Save As or rename moves where images come from.
|
||||
fn observed(&mut self, id: u64, view: &Entity<MarkView>, cx: &mut Context<Self>) {
|
||||
self.watch_folders(cx);
|
||||
self.look_once(id, cx);
|
||||
let changed = view.read(cx).changed();
|
||||
self.autosave(id, changed, cx);
|
||||
let recheck = self.tab_mut(id).is_some_and(|tab| {
|
||||
|
||||
+123
-1
@@ -2,7 +2,9 @@
|
||||
|
||||
use std::{io, path::Path};
|
||||
|
||||
use gpui::{Context, actions};
|
||||
use ely_gpui_component::{documents::DocumentLook, primitives::Severity, theme::ActiveTheme as _};
|
||||
use ely_office::prelude::*;
|
||||
use gpui::{App, Context, actions, rems};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::desk::Desk;
|
||||
@@ -53,6 +55,36 @@ impl Default for Look {
|
||||
}
|
||||
}
|
||||
|
||||
/// A serif face each system carries.
|
||||
const SERIF: &str = if cfg!(target_os = "linux") {
|
||||
"DejaVu Serif"
|
||||
} else {
|
||||
"Georgia"
|
||||
};
|
||||
|
||||
impl Look {
|
||||
/// How the document shows text by this look.
|
||||
pub fn document(&self, cx: &App) -> DocumentLook {
|
||||
let measure = match self.width {
|
||||
Width::Narrow => 36.0,
|
||||
Width::Medium => 48.0,
|
||||
Width::Wide => 64.0,
|
||||
};
|
||||
let font = match self.font {
|
||||
Font::Sans => None,
|
||||
Font::Serif => Some(SERIF.into()),
|
||||
Font::Mono => Some(cx.theme().mono_family.clone()),
|
||||
};
|
||||
DocumentLook {
|
||||
focus: self.focus,
|
||||
typewriter: self.typewriter,
|
||||
measure: Some(rems(measure)),
|
||||
font,
|
||||
scale: self.size as f32 / 100.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The kept look; none kept is the default.
|
||||
pub fn load(file: &Path) -> io::Result<Look> {
|
||||
match std::fs::read(file) {
|
||||
@@ -74,7 +106,11 @@ impl Desk {
|
||||
let json = serde_json::to_vec_pretty(&self.look).expect("a look serializes");
|
||||
if let Err(error) = ely_files::save_atomic(&self.look_file, &json, 0) {
|
||||
log::error!("mark: the look did not save: {error}");
|
||||
let said =
|
||||
ely_ui::i18n::text(cx, "office.error.engine", &[("error", &error.to_string())]);
|
||||
self.toast(said, Severity::Danger, cx);
|
||||
}
|
||||
self.apply_look(cx);
|
||||
let menus = crate::keys::menus(&self.look, cx);
|
||||
ely_ui::set_document_menus(
|
||||
ely_platform::AppId::Mark,
|
||||
@@ -85,6 +121,31 @@ impl Desk {
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
/// Every tab's document takes the look.
|
||||
fn apply_look(&mut self, cx: &mut Context<Self>) {
|
||||
let look = self.look.document(cx);
|
||||
let documents: Vec<_> = self
|
||||
.core
|
||||
.tabs
|
||||
.iter()
|
||||
.map(|tab| tab.view.read(cx).document().clone())
|
||||
.collect();
|
||||
for document in documents {
|
||||
document.update(cx, |document, cx| document.set_look(look.clone(), cx));
|
||||
}
|
||||
}
|
||||
|
||||
/// A new tab's document takes the look once.
|
||||
pub fn look_once(&mut self, id: u64, cx: &mut Context<Self>) {
|
||||
let look = self.look.document(cx);
|
||||
let Some(tab) = self.tab_mut(id).filter(|tab| !tab.extra.looked) else {
|
||||
return;
|
||||
};
|
||||
tab.extra.looked = true;
|
||||
let document = tab.view.read(cx).document().clone();
|
||||
document.update(cx, |document, cx| document.set_look(look, cx));
|
||||
}
|
||||
|
||||
pub fn look_actions(element: gpui::Div, cx: &mut Context<Self>) -> gpui::Div {
|
||||
use gpui::InteractiveElement as _;
|
||||
let step = SIZES.2;
|
||||
@@ -133,6 +194,67 @@ impl Desk {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use ely_gpui_component::documents::DocumentLook;
|
||||
use gpui::{Entity, TestAppContext, VisualTestContext, rems};
|
||||
|
||||
use crate::desk::{
|
||||
Desk,
|
||||
tests::{open, start},
|
||||
};
|
||||
|
||||
fn document_look(desk: &Entity<Desk>, cx: &mut VisualTestContext) -> DocumentLook {
|
||||
desk.read_with(cx, |desk, cx| {
|
||||
let view = desk.active_view().expect("a tab");
|
||||
view.read(cx).document().read(cx).look().clone()
|
||||
})
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn a_new_tab_takes_the_kept_look(cx: &mut TestAppContext) {
|
||||
let (data, files) = (
|
||||
tempfile::tempdir().expect("data"),
|
||||
tempfile::tempdir().expect("files"),
|
||||
);
|
||||
let kept = r#"{"focus":true,"typewriter":true,"width":"narrow","font":"serif","size":120}"#;
|
||||
std::fs::write(data.path().join("look.json"), kept).expect("a look");
|
||||
let path = files.path().join("a.md");
|
||||
std::fs::write(
|
||||
&path, "a
|
||||
",
|
||||
)
|
||||
.expect("a file");
|
||||
let (desk, cx) = start(cx, data.path());
|
||||
open(&desk, &path, cx);
|
||||
let look = document_look(&desk, cx);
|
||||
assert!(look.focus && look.typewriter);
|
||||
assert_eq!((look.measure, look.scale), (Some(rems(36.0)), 1.2));
|
||||
assert_eq!(look.font.as_deref(), Some(super::SERIF));
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn a_menu_change_reaches_open_tabs_and_is_kept(cx: &mut TestAppContext) {
|
||||
let (data, files) = (
|
||||
tempfile::tempdir().expect("data"),
|
||||
tempfile::tempdir().expect("files"),
|
||||
);
|
||||
let path = files.path().join("a.md");
|
||||
std::fs::write(
|
||||
&path, "a
|
||||
",
|
||||
)
|
||||
.expect("a file");
|
||||
let (desk, cx) = start(cx, data.path());
|
||||
open(&desk, &path, cx);
|
||||
let focus = desk.read_with(cx, |desk, _| desk.core.focus.clone());
|
||||
cx.update(|window, cx| window.focus(&focus, cx));
|
||||
cx.dispatch_action(super::Wide);
|
||||
cx.dispatch_action(super::Larger);
|
||||
let look = document_look(&desk, cx);
|
||||
assert_eq!((look.measure, look.scale), (Some(rems(64.0)), 1.1));
|
||||
let kept = std::fs::read_to_string(data.path().join("look.json")).expect("kept");
|
||||
assert!(kept.contains("\"wide\"") && kept.contains("110"), "{kept}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_kept_look_reads_back_and_none_is_default() {
|
||||
let dir = tempfile::tempdir().expect("a temp dir");
|
||||
|
||||
@@ -55,6 +55,8 @@ pub struct Extra {
|
||||
pub restored: bool,
|
||||
/// Disk reads started; only the newest lands.
|
||||
pub reads: u64,
|
||||
/// The writing view reached its document.
|
||||
pub looked: bool,
|
||||
}
|
||||
|
||||
impl Extra {
|
||||
@@ -79,6 +81,7 @@ impl Default for Extra {
|
||||
pointing: false,
|
||||
restored: false,
|
||||
reads: 0,
|
||||
looked: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user