Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 18 additions & 5 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"version": "0.2.0",
"configurations": [
{
"name": "Launch Debug (Windows)",
"name": "Launch edit (Windows)",
"preLaunchTask": "rust: cargo build",
"type": "cppvsdbg",
"request": "launch",
Expand All @@ -14,7 +14,7 @@
],
},
{
"name": "Launch Debug (GDB)",
"name": "Launch edit (GDB, Linux)",
"preLaunchTask": "rust: cargo build",
"type": "cppdbg",
"request": "launch",
Expand All @@ -27,15 +27,28 @@
],
},
{
"name": "Launch Debug (LLDB)",
// NOTE for macOS: In order for this task to work you have to:
// 1. Run the "Fix externalConsole on macOS" task once
// 2. Add the following to your VS Code settings:
// "lldb-dap.environment": {
// "LLDB_LAUNCH_FLAG_LAUNCH_IN_TTY": "YES"
// }
"name": "Launch edit (lldb-dap, macOS)",
"preLaunchTask": "rust: cargo build",
"type": "lldb",
"type": "lldb-dap",
"request": "launch",
"program": "${workspaceFolder}/target/debug/edit",
"cwd": "${workspaceFolder}",
"args": [
"${workspaceFolder}/crates/edit/src/bin/edit/main.rs"
],
}
},
{
// This is a workaround for https://github.com/microsoft/vscode-cpptools/issues/5079
"name": "Fix externalConsole on macOS",
"type": "node-terminal",
"request": "launch",
"command": "osascript -e 'tell application \"Terminal\"\ndo script \"echo hello\"\nend tell'"
},
]
}
1 change: 1 addition & 0 deletions crates/edit/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ name = "lib"
harness = false

[features]
# Display editor latency in the top-right corner
debug-latency = []

[dependencies]
Expand Down
6 changes: 3 additions & 3 deletions crates/edit/src/bin/edit/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ mod localization;
mod state;

use std::borrow::Cow;
#[cfg(feature = "debug-latency")]
use std::fmt::Write;
use std::path::{Path, PathBuf};
use std::time::Duration;
use std::{env, process};
Expand All @@ -23,7 +21,7 @@ use draw_filepicker::*;
use draw_menubar::*;
use draw_statusbar::*;
use edit::framebuffer::{self, IndexedColor};
use edit::helpers::{CoordType, KIBI, MEBI, MetricFormatter, Rect, Size};
use edit::helpers::*;
use edit::input::{self, kbmod, vk};
use edit::oklab::StraightRgba;
use edit::tui::*;
Expand Down Expand Up @@ -178,6 +176,8 @@ fn run() -> apperr::Result<()> {

#[cfg(feature = "debug-latency")]
{
use std::fmt::Write as _;

// Print the number of passes and latency in the top right corner.
let time_end = std::time::Instant::now();
let status = time_end - time_beg;
Expand Down
22 changes: 16 additions & 6 deletions crates/edit/src/framebuffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ pub struct Framebuffer {
/// of the palette as [dark, light], unless the palette is recognized
/// as a light them, in which case it swaps them.
auto_colors: [StraightRgba; 2],
/// Above this lightness value, we consider a color to be "light".
auto_color_threshold: f32,
/// A cache table for previously contrasted colors.
/// See: <https://fgiesen.wordpress.com/2019/02/11/cache-tables/>
contrast_colors: [Cell<(StraightRgba, StraightRgba)>; CACHE_TABLE_SIZE],
Expand All @@ -125,6 +127,7 @@ impl Framebuffer {
DEFAULT_THEME[IndexedColor::Black as usize],
DEFAULT_THEME[IndexedColor::BrightWhite as usize],
],
auto_color_threshold: 0.5,
contrast_colors: [const { Cell::new((StraightRgba::zero(), StraightRgba::zero())) };
CACHE_TABLE_SIZE],
background_fill: DEFAULT_THEME[IndexedColor::Background as usize],
Expand All @@ -145,7 +148,17 @@ impl Framebuffer {
self.indexed_colors[IndexedColor::Black as usize],
self.indexed_colors[IndexedColor::BrightWhite as usize],
];
if !Self::is_dark(self.auto_colors[0]) {

// It's not guaranteed that Black is actually dark and BrightWhite light (vice versa for a light theme).
// Such is the case with macOS 26's "Clear Dark" theme (and probably a lot other themes).
// Its black is #35424C (l=0.3716; oof!) and bright white is #E5EFF5 (l=0.9464).
// If we have a color such as #43698A (l=0.5065), which is l>0.5 ("light") and need a contrasting color,
// we need that to be #E5EFF5, even though that's also l>0.5. With a midpoint of 0.659, we get that right.
let lightness = self.auto_colors.map(|c| c.as_oklab().lightness());
self.auto_color_threshold = (lightness[0] + lightness[1]) * 0.5;

// Ensure [0] is dark and [1] is light.
if lightness[0] > lightness[1] {
self.auto_colors.swap(0, 1);
}
}
Expand Down Expand Up @@ -346,15 +359,12 @@ impl Framebuffer {
#[cold]
fn contrasted_slow(&self, color: StraightRgba) -> StraightRgba {
let idx = (color.to_ne() as usize).wrapping_mul(HASH_MULTIPLIER) >> CACHE_TABLE_SHIFT;
let contrast = self.auto_colors[Self::is_dark(color) as usize];
let is_dark = color.as_oklab().lightness() < self.auto_color_threshold;
let contrast = self.auto_colors[is_dark as usize];
self.contrast_colors[idx].set((color, contrast));
contrast
}

fn is_dark(color: StraightRgba) -> bool {
color.as_oklab().lightness() < 0.5
}

/// Blends the given sRGB color onto the background bitmap.
///
/// TODO: The current approach blends foreground/background independently,
Expand Down
3 changes: 3 additions & 0 deletions crates/edit/src/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ pub struct Size {
}

impl Size {
pub const MIN: Self = Self { width: 0, height: 0 };
pub const MAX: Self = Self { width: CoordType::MAX, height: CoordType::MAX };

pub fn as_rect(&self) -> Rect {
Rect { left: 0, top: 0, right: self.width, bottom: self.height }
}
Expand Down
4 changes: 2 additions & 2 deletions crates/edit/src/sys/unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use std::fs::File;
use std::mem::{self, ManuallyDrop, MaybeUninit};
use std::os::fd::{AsRawFd as _, FromRawFd as _};
use std::path::Path;
use std::ptr::{self, NonNull, null_mut};
use std::ptr::{NonNull, null_mut};
use std::{thread, time};

use stdext::arena::{Arena, ArenaString, scratch_arena};
Expand Down Expand Up @@ -203,7 +203,7 @@ pub fn read_stdin(arena: &Arena, mut timeout: time::Duration) -> Option<ArenaStr
tv_sec: timeout.as_secs() as libc::time_t,
tv_nsec: timeout.subsec_nanos() as libc::c_long,
};
ret = libc::ppoll(&mut pollfd, 1, &ts, ptr::null());
ret = libc::ppoll(&mut pollfd, 1, &ts, std::ptr::null());
}
#[cfg(not(target_os = "linux"))]
{
Expand Down
19 changes: 19 additions & 0 deletions crates/stdext/src/arena/string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,13 @@ impl<'a> ArenaString<'a> {
}
}

#[must_use]
pub fn from_iter<T: IntoIterator<Item = char>>(arena: &'a Arena, iter: T) -> Self {
let mut s = Self::new_in(arena);
s.extend(iter);
s
}

/// It's empty.
pub fn is_empty(&self) -> bool {
self.vec.is_empty()
Expand Down Expand Up @@ -284,6 +291,18 @@ impl fmt::Write for ArenaString<'_> {
}
}

impl Extend<char> for ArenaString<'_> {
fn extend<I: IntoIterator<Item = char>>(&mut self, iter: I) {
let iterator = iter.into_iter();
let (lower_bound, _) = iterator.size_hint();
self.reserve(lower_bound);
iterator.for_each(move |c| self.push(c));
}

// TODO: This is where I'd put `extend_one` and `extend_reserve` impls, *but as always*,
// essential stdlib functions are unstable and that means we can't have them.
}

#[macro_export]
macro_rules! arena_format {
($arena:expr, $($arg:tt)*) => {{
Expand Down