theme palette, command bridge, missing shortcuts
This commit is contained in:
parent
36895cd548
commit
6f36f9c3df
|
|
@ -6,11 +6,6 @@ import UniformTypeIdentifiers
|
|||
extension Notification.Name {
|
||||
static let focusEditor = Notification.Name("focusEditor")
|
||||
static let focusTitle = Notification.Name("focusTitle")
|
||||
static let formatDocument = Notification.Name("formatDocument")
|
||||
static let insertTable = Notification.Name("insertTable")
|
||||
static let boldSelection = Notification.Name("boldSelection")
|
||||
static let italicizeSelection = Notification.Name("italicizeSelection")
|
||||
static let smartEval = Notification.Name("smartEval")
|
||||
}
|
||||
|
||||
class WindowController {
|
||||
|
|
@ -63,6 +58,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
|||
observeDocumentTitle()
|
||||
|
||||
observeDocumentText()
|
||||
syncThemeToViewport()
|
||||
|
||||
DocumentBrowserController.shared = DocumentBrowserController(appState: appState)
|
||||
|
||||
|
|
@ -281,19 +277,19 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
|||
}
|
||||
|
||||
@objc private func boldSelection() {
|
||||
NotificationCenter.default.post(name: .boldSelection, object: nil)
|
||||
viewport?.sendCommand(1)
|
||||
}
|
||||
|
||||
@objc private func italicizeSelection() {
|
||||
NotificationCenter.default.post(name: .italicizeSelection, object: nil)
|
||||
viewport?.sendCommand(2)
|
||||
}
|
||||
|
||||
@objc private func insertTable() {
|
||||
NotificationCenter.default.post(name: .insertTable, object: nil)
|
||||
viewport?.sendCommand(3)
|
||||
}
|
||||
|
||||
@objc private func smartEval() {
|
||||
NotificationCenter.default.post(name: .smartEval, object: nil)
|
||||
viewport?.sendCommand(4)
|
||||
}
|
||||
|
||||
@objc private func openNote() {
|
||||
|
|
@ -412,7 +408,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
|||
}()
|
||||
|
||||
@objc private func formatDocument() {
|
||||
NotificationCenter.default.post(name: .formatDocument, object: nil)
|
||||
viewport?.sendCommand(10)
|
||||
}
|
||||
|
||||
@objc private func openSettings() {
|
||||
|
|
@ -421,9 +417,24 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
|||
|
||||
@objc private func settingsDidChange() {
|
||||
window.backgroundColor = Theme.current.base
|
||||
syncThemeToViewport()
|
||||
window.contentView?.needsDisplay = true
|
||||
}
|
||||
|
||||
private func syncThemeToViewport() {
|
||||
let mode = ConfigManager.shared.themeMode
|
||||
let name: String
|
||||
switch mode {
|
||||
case "dark": name = "mocha"
|
||||
case "light": name = "latte"
|
||||
default:
|
||||
let appearance = NSApp.effectiveAppearance
|
||||
let isDark = appearance.bestMatch(from: [.darkAqua, .aqua]) == .darkAqua
|
||||
name = isDark ? "mocha" : "latte"
|
||||
}
|
||||
viewport?.setTheme(name)
|
||||
}
|
||||
|
||||
@objc private func toggleBrowser() {
|
||||
DocumentBrowserController.shared?.toggle()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -159,7 +159,7 @@ class IcedViewportView: NSView {
|
|||
|
||||
if cmd && !shift {
|
||||
switch chars {
|
||||
case "a", "b", "c", "i", "v", "x", "z", "p", "t",
|
||||
case "a", "b", "c", "e", "f", "g", "i", "v", "x", "z", "p", "t",
|
||||
"=", "+", "-", "0":
|
||||
keyDown(with: event)
|
||||
return true
|
||||
|
|
@ -214,4 +214,16 @@ class IcedViewportView: NSView {
|
|||
viewport_free_string(cstr)
|
||||
return result
|
||||
}
|
||||
|
||||
func sendCommand(_ command: UInt32) {
|
||||
guard let h = viewportHandle else { return }
|
||||
viewport_send_command(h, command)
|
||||
}
|
||||
|
||||
func setTheme(_ name: String) {
|
||||
guard let h = viewportHandle else { return }
|
||||
name.withCString { cstr in
|
||||
viewport_set_theme(h, cstr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,4 +53,8 @@ char *viewport_get_text(struct ViewportHandle *handle);
|
|||
|
||||
void viewport_free_string(char *s);
|
||||
|
||||
void viewport_set_theme(struct ViewportHandle *_handle, const char *name);
|
||||
|
||||
void viewport_send_command(struct ViewportHandle *handle, uint32_t command);
|
||||
|
||||
#endif /* ACORD_VIEWPORT_H */
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ use iced_widget::container;
|
|||
use iced_widget::markdown;
|
||||
use iced_widget::text_editor::{self, Action, Binding, Cursor, KeyPress, Motion, Position, Status, Style};
|
||||
use iced_wgpu::core::text::highlighter::Format;
|
||||
use crate::palette;
|
||||
use crate::syntax::{self, SyntaxHighlighter, SyntaxSettings};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
|
@ -48,17 +49,18 @@ pub struct EditorState {
|
|||
}
|
||||
|
||||
fn md_style() -> markdown::Style {
|
||||
let p = palette::current();
|
||||
markdown::Style {
|
||||
font: Font::default(),
|
||||
inline_code_highlight: Highlight {
|
||||
background: Color::from_rgb(0.188, 0.188, 0.259).into(),
|
||||
background: p.surface0.into(),
|
||||
border: border::rounded(4),
|
||||
},
|
||||
inline_code_padding: padding::left(2).right(2),
|
||||
inline_code_color: Color::from_rgb(0.651, 0.890, 0.631),
|
||||
inline_code_color: p.green,
|
||||
inline_code_font: Font::MONOSPACE,
|
||||
code_block_font: Font::MONOSPACE,
|
||||
link_color: Color::from_rgb(0.537, 0.706, 0.980),
|
||||
link_color: p.blue,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -402,12 +404,15 @@ impl EditorState {
|
|||
)
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.style(|_theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(Color::from_rgb(0.08, 0.08, 0.10))),
|
||||
border: Border::default(),
|
||||
text_color: Some(Color::from_rgb(0.804, 0.839, 0.957)),
|
||||
shadow: Shadow::default(),
|
||||
snap: false,
|
||||
.style(|_theme: &Theme| {
|
||||
let p = palette::current();
|
||||
container::Style {
|
||||
background: Some(Background::Color(p.base)),
|
||||
border: Border::default(),
|
||||
text_color: Some(p.text),
|
||||
shadow: Shadow::default(),
|
||||
snap: false,
|
||||
}
|
||||
})
|
||||
.into()
|
||||
} else {
|
||||
|
|
@ -420,12 +425,15 @@ impl EditorState {
|
|||
.padding(Padding { top: top_pad, right: 8.0, bottom: 8.0, left: 8.0 })
|
||||
.wrapping(Wrapping::Word)
|
||||
.key_binding(macos_key_binding)
|
||||
.style(|_theme, _status| Style {
|
||||
background: Background::Color(Color::from_rgb(0.08, 0.08, 0.10)),
|
||||
border: Border::default(),
|
||||
placeholder: Color::from_rgb(0.4, 0.4, 0.4),
|
||||
value: Color::WHITE,
|
||||
selection: Color::from_rgba(0.3, 0.5, 0.8, 0.4),
|
||||
.style(|_theme, _status| {
|
||||
let p = palette::current();
|
||||
Style {
|
||||
background: Background::Color(p.base),
|
||||
border: Border::default(),
|
||||
placeholder: p.overlay0,
|
||||
value: p.text,
|
||||
selection: Color { a: 0.4, ..p.blue },
|
||||
}
|
||||
});
|
||||
|
||||
let settings = SyntaxSettings {
|
||||
|
|
@ -478,18 +486,21 @@ impl EditorState {
|
|||
iced_widget::text(format!("{mode_label} Ln {line}, Col {col}"))
|
||||
.font(Font::MONOSPACE)
|
||||
.size(11.0)
|
||||
.color(Color::from_rgb(0.55, 0.55, 0.55))
|
||||
.color(palette::current().overlay1)
|
||||
.into(),
|
||||
])
|
||||
)
|
||||
.width(Length::Fill)
|
||||
.padding(Padding { top: 3.0, right: 10.0, bottom: 3.0, left: 10.0 })
|
||||
.style(|_theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(Color::from_rgb(0.12, 0.12, 0.14))),
|
||||
border: Border::default(),
|
||||
text_color: None,
|
||||
shadow: Shadow::default(),
|
||||
snap: false,
|
||||
.style(|_theme: &Theme| {
|
||||
let p = palette::current();
|
||||
container::Style {
|
||||
background: Some(Background::Color(p.mantle)),
|
||||
border: Border::default(),
|
||||
text_color: None,
|
||||
shadow: Shadow::default(),
|
||||
snap: false,
|
||||
}
|
||||
});
|
||||
|
||||
let mut col_items: Vec<Element<'_, Message, Theme, iced_wgpu::Renderer>> =
|
||||
|
|
@ -539,7 +550,7 @@ impl canvas::Program<Message, Theme, iced_wgpu::Renderer> for Gutter {
|
|||
frame.fill_rectangle(
|
||||
Point::ORIGIN,
|
||||
bounds.size(),
|
||||
Color::from_rgb(0.06, 0.06, 0.08),
|
||||
palette::current().crust,
|
||||
);
|
||||
|
||||
let first_visible = (self.scroll_offset / lh).floor() as usize;
|
||||
|
|
@ -572,10 +583,11 @@ impl canvas::Program<Message, Theme, iced_wgpu::Renderer> for Gutter {
|
|||
continue;
|
||||
}
|
||||
source_num += 1;
|
||||
let p = palette::current();
|
||||
let color = if line_idx == self.cursor_line {
|
||||
Color::from_rgb(0.55, 0.55, 0.62)
|
||||
p.overlay1
|
||||
} else {
|
||||
Color::from_rgb(0.35, 0.35, 0.42)
|
||||
p.surface2
|
||||
};
|
||||
frame.fill_text(canvas::Text {
|
||||
content: format!("{}", source_num),
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ use raw_window_handle::{
|
|||
};
|
||||
|
||||
use crate::editor::{EditorState, Message};
|
||||
use crate::palette;
|
||||
use crate::ViewportHandle;
|
||||
|
||||
struct MacClipboard;
|
||||
|
|
@ -209,10 +210,9 @@ pub fn render(handle: &mut ViewportHandle) {
|
|||
ui.draw(&mut handle.renderer, &theme, &style, handle.cursor);
|
||||
handle.cache = ui.into_cache();
|
||||
|
||||
let bg = Color::from_rgb(0.08, 0.08, 0.10);
|
||||
handle
|
||||
.renderer
|
||||
.present(Some(bg), handle.format, &view, &handle.viewport);
|
||||
.present(Some(palette::current().base), handle.format, &view, &handle.viewport);
|
||||
|
||||
frame.present();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ use std::ffi::{c_char, c_void, CStr, CString};
|
|||
mod bridge;
|
||||
mod editor;
|
||||
mod handle;
|
||||
pub mod palette;
|
||||
mod syntax;
|
||||
|
||||
pub use acord_core::*;
|
||||
|
|
@ -172,3 +173,34 @@ pub extern "C" fn viewport_free_string(s: *mut c_char) {
|
|||
if s.is_null() { return; }
|
||||
unsafe { drop(CString::from_raw(s)); }
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn viewport_set_theme(_handle: *mut ViewportHandle, name: *const c_char) {
|
||||
let s = if name.is_null() {
|
||||
"mocha"
|
||||
} else {
|
||||
unsafe { CStr::from_ptr(name) }.to_str().unwrap_or("mocha")
|
||||
};
|
||||
palette::set_theme(s);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn viewport_send_command(handle: *mut ViewportHandle, command: u32) {
|
||||
let h = match unsafe { handle.as_mut() } {
|
||||
Some(h) => h,
|
||||
None => return,
|
||||
};
|
||||
let msg = match command {
|
||||
1 => editor::Message::ToggleBold,
|
||||
2 => editor::Message::ToggleItalic,
|
||||
3 => editor::Message::InsertTable,
|
||||
4 => editor::Message::SmartEval,
|
||||
5 => editor::Message::Evaluate,
|
||||
6 => editor::Message::TogglePreview,
|
||||
7 => editor::Message::ZoomIn,
|
||||
8 => editor::Message::ZoomOut,
|
||||
9 => editor::Message::ZoomReset,
|
||||
_ => return,
|
||||
};
|
||||
h.state.update(msg);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,106 @@
|
|||
use iced_wgpu::core::Color;
|
||||
use std::cell::RefCell;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Palette {
|
||||
pub rosewater: Color,
|
||||
pub flamingo: Color,
|
||||
pub pink: Color,
|
||||
pub mauve: Color,
|
||||
pub red: Color,
|
||||
pub maroon: Color,
|
||||
pub peach: Color,
|
||||
pub yellow: Color,
|
||||
pub green: Color,
|
||||
pub teal: Color,
|
||||
pub sky: Color,
|
||||
pub sapphire: Color,
|
||||
pub blue: Color,
|
||||
pub lavender: Color,
|
||||
pub text: Color,
|
||||
pub subtext1: Color,
|
||||
pub subtext0: Color,
|
||||
pub overlay2: Color,
|
||||
pub overlay1: Color,
|
||||
pub overlay0: Color,
|
||||
pub surface2: Color,
|
||||
pub surface1: Color,
|
||||
pub surface0: Color,
|
||||
pub base: Color,
|
||||
pub mantle: Color,
|
||||
pub crust: Color,
|
||||
}
|
||||
|
||||
pub static MOCHA: Palette = Palette {
|
||||
rosewater: Color::from_rgb(0.961, 0.878, 0.863),
|
||||
flamingo: Color::from_rgb(0.949, 0.804, 0.804),
|
||||
pink: Color::from_rgb(0.961, 0.761, 0.906),
|
||||
mauve: Color::from_rgb(0.796, 0.651, 0.969),
|
||||
red: Color::from_rgb(0.953, 0.545, 0.659),
|
||||
maroon: Color::from_rgb(0.922, 0.627, 0.675),
|
||||
peach: Color::from_rgb(0.980, 0.702, 0.529),
|
||||
yellow: Color::from_rgb(0.976, 0.886, 0.686),
|
||||
green: Color::from_rgb(0.651, 0.890, 0.631),
|
||||
teal: Color::from_rgb(0.580, 0.886, 0.835),
|
||||
sky: Color::from_rgb(0.537, 0.863, 0.922),
|
||||
sapphire: Color::from_rgb(0.455, 0.780, 0.925),
|
||||
blue: Color::from_rgb(0.537, 0.706, 0.980),
|
||||
lavender: Color::from_rgb(0.706, 0.745, 0.996),
|
||||
text: Color::from_rgb(0.804, 0.839, 0.957),
|
||||
subtext1: Color::from_rgb(0.729, 0.761, 0.871),
|
||||
subtext0: Color::from_rgb(0.651, 0.678, 0.784),
|
||||
overlay2: Color::from_rgb(0.576, 0.600, 0.698),
|
||||
overlay1: Color::from_rgb(0.498, 0.518, 0.612),
|
||||
overlay0: Color::from_rgb(0.424, 0.439, 0.525),
|
||||
surface2: Color::from_rgb(0.345, 0.357, 0.439),
|
||||
surface1: Color::from_rgb(0.271, 0.278, 0.353),
|
||||
surface0: Color::from_rgb(0.192, 0.196, 0.267),
|
||||
base: Color::from_rgb(0.118, 0.118, 0.180),
|
||||
mantle: Color::from_rgb(0.094, 0.094, 0.145),
|
||||
crust: Color::from_rgb(0.067, 0.067, 0.106),
|
||||
};
|
||||
|
||||
pub static LATTE: Palette = Palette {
|
||||
rosewater: Color::from_rgb(0.863, 0.541, 0.471),
|
||||
flamingo: Color::from_rgb(0.867, 0.471, 0.471),
|
||||
pink: Color::from_rgb(0.918, 0.463, 0.796),
|
||||
mauve: Color::from_rgb(0.533, 0.224, 0.937),
|
||||
red: Color::from_rgb(0.824, 0.059, 0.224),
|
||||
maroon: Color::from_rgb(0.902, 0.271, 0.325),
|
||||
peach: Color::from_rgb(0.996, 0.392, 0.043),
|
||||
yellow: Color::from_rgb(0.875, 0.557, 0.114),
|
||||
green: Color::from_rgb(0.251, 0.627, 0.169),
|
||||
teal: Color::from_rgb(0.090, 0.573, 0.600),
|
||||
sky: Color::from_rgb(0.016, 0.647, 0.898),
|
||||
sapphire: Color::from_rgb(0.125, 0.624, 0.710),
|
||||
blue: Color::from_rgb(0.118, 0.400, 0.961),
|
||||
lavender: Color::from_rgb(0.447, 0.529, 0.992),
|
||||
text: Color::from_rgb(0.298, 0.310, 0.412),
|
||||
subtext1: Color::from_rgb(0.361, 0.373, 0.467),
|
||||
subtext0: Color::from_rgb(0.424, 0.435, 0.522),
|
||||
overlay2: Color::from_rgb(0.486, 0.498, 0.576),
|
||||
overlay1: Color::from_rgb(0.549, 0.561, 0.631),
|
||||
overlay0: Color::from_rgb(0.612, 0.627, 0.690),
|
||||
surface2: Color::from_rgb(0.675, 0.690, 0.745),
|
||||
surface1: Color::from_rgb(0.737, 0.753, 0.800),
|
||||
surface0: Color::from_rgb(0.800, 0.816, 0.855),
|
||||
base: Color::from_rgb(0.937, 0.945, 0.961),
|
||||
mantle: Color::from_rgb(0.902, 0.914, 0.937),
|
||||
crust: Color::from_rgb(0.863, 0.878, 0.910),
|
||||
};
|
||||
|
||||
thread_local! {
|
||||
static CURRENT: RefCell<&'static Palette> = const { RefCell::new(&MOCHA) };
|
||||
}
|
||||
|
||||
pub fn current() -> &'static Palette {
|
||||
CURRENT.with(|c| *c.borrow())
|
||||
}
|
||||
|
||||
pub fn set_theme(name: &str) {
|
||||
let pal = match name {
|
||||
"latte" | "light" => &LATTE,
|
||||
_ => &MOCHA,
|
||||
};
|
||||
CURRENT.with(|c| *c.borrow_mut() = pal);
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ use iced_wgpu::core::text::highlighter;
|
|||
use iced_wgpu::core::Color;
|
||||
use acord_core::highlight::{highlight_source, HighlightSpan};
|
||||
use crate::editor::{RESULT_PREFIX, ERROR_PREFIX};
|
||||
use crate::palette;
|
||||
|
||||
pub const EVAL_RESULT_KIND: u8 = 24;
|
||||
pub const EVAL_ERROR_KIND: u8 = 25;
|
||||
|
|
@ -107,33 +108,34 @@ impl highlighter::Highlighter for SyntaxHighlighter {
|
|||
}
|
||||
|
||||
pub fn highlight_color(kind: u8) -> Color {
|
||||
let p = palette::current();
|
||||
match kind {
|
||||
0 => Color::from_rgb(0.804, 0.569, 0.945), // keyword - mauve
|
||||
1 => Color::from_rgb(0.537, 0.706, 0.980), // function - blue
|
||||
2 => Color::from_rgb(0.604, 0.831, 0.898), // function.builtin - teal
|
||||
3 => Color::from_rgb(0.976, 0.827, 0.522), // type - yellow
|
||||
4 => Color::from_rgb(0.976, 0.827, 0.522), // type.builtin - yellow
|
||||
5 => Color::from_rgb(0.569, 0.878, 0.800), // constructor - teal
|
||||
6 => Color::from_rgb(0.988, 0.702, 0.529), // constant - peach
|
||||
7 => Color::from_rgb(0.988, 0.702, 0.529), // constant.builtin - peach
|
||||
8 => Color::from_rgb(0.651, 0.890, 0.631), // string - green
|
||||
9 => Color::from_rgb(0.988, 0.702, 0.529), // number - peach
|
||||
10 => Color::from_rgb(0.424, 0.443, 0.537), // comment - overlay0
|
||||
11 => Color::from_rgb(0.804, 0.839, 0.957), // variable - text
|
||||
12 => Color::from_rgb(0.949, 0.604, 0.584), // variable.builtin - red
|
||||
13 => Color::from_rgb(0.949, 0.773, 0.584), // variable.parameter - flamingo
|
||||
14 => Color::from_rgb(0.604, 0.831, 0.898), // operator - sky
|
||||
15 => Color::from_rgb(0.580, 0.612, 0.733), // punctuation - overlay2
|
||||
16 => Color::from_rgb(0.580, 0.612, 0.733), // punctuation.bracket - overlay2
|
||||
17 => Color::from_rgb(0.580, 0.612, 0.733), // punctuation.delimiter - overlay2
|
||||
18 => Color::from_rgb(0.537, 0.706, 0.980), // property - blue
|
||||
19 => Color::from_rgb(0.804, 0.569, 0.945), // tag - mauve
|
||||
20 => Color::from_rgb(0.976, 0.827, 0.522), // attribute - yellow
|
||||
21 => Color::from_rgb(0.569, 0.878, 0.800), // label - teal
|
||||
22 => Color::from_rgb(0.949, 0.604, 0.584), // escape - red
|
||||
23 => Color::from_rgb(0.804, 0.839, 0.957), // embedded - text
|
||||
24 => Color::from_rgb(0.651, 0.890, 0.631), // eval result - green
|
||||
25 => Color::from_rgb(0.890, 0.400, 0.400), // eval error - muted red
|
||||
_ => Color::from_rgb(0.804, 0.839, 0.957), // default text
|
||||
0 => p.mauve,
|
||||
1 => p.blue,
|
||||
2 => p.teal,
|
||||
3 => p.yellow,
|
||||
4 => p.yellow,
|
||||
5 => p.teal,
|
||||
6 => p.peach,
|
||||
7 => p.peach,
|
||||
8 => p.green,
|
||||
9 => p.peach,
|
||||
10 => p.overlay0,
|
||||
11 => p.text,
|
||||
12 => p.red,
|
||||
13 => p.flamingo,
|
||||
14 => p.sky,
|
||||
15 => p.overlay2,
|
||||
16 => p.overlay2,
|
||||
17 => p.overlay2,
|
||||
18 => p.blue,
|
||||
19 => p.mauve,
|
||||
20 => p.yellow,
|
||||
21 => p.teal,
|
||||
22 => p.red,
|
||||
23 => p.text,
|
||||
24 => p.green,
|
||||
25 => p.maroon,
|
||||
_ => p.text,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue