Skip to content
Draft
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
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ windows = { version = "0.54.0", features = [
"Win32_System_LibraryLoader",
"Win32_System_Memory",
"Win32_System_Ole",
"Win32_System_SystemInformation",
"Win32_System_Threading",
"Win32_UI_Controls",
"Win32_UI_Controls_Dialogs",
Expand Down
35 changes: 35 additions & 0 deletions src/app/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ pub const DEFAULT_ZOOM_LEVEL: i32 = 0;
/// Scintilla's supported zoom range (points added to the base font size).
pub const MIN_ZOOM_LEVEL: i32 = -10;
pub const MAX_ZOOM_LEVEL: i32 = 20;
pub const DEFAULT_EDITOR_FONT_NAME: &str = "Consolas";
pub const DEFAULT_EDITOR_FONT_SIZE: i32 = 11;
pub const MIN_EDITOR_FONT_SIZE: i32 = 6;
pub const MAX_EDITOR_FONT_SIZE: i32 = 72;

#[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq, Eq, Default)]
#[serde(rename_all = "lowercase")]
Expand Down Expand Up @@ -73,6 +77,13 @@ pub struct UiSettings {
/// [`MIN_ZOOM_LEVEL`]..=[`MAX_ZOOM_LEVEL`].
#[serde(default)]
pub zoom_level: i32,
/// `settings.json`: editor font family name (e.g. "Consolas").
#[serde(default = "default_editor_font_name")]
pub editor_font_name: String,
/// `settings.json`: editor base font size in points, clamped to
/// [`MIN_EDITOR_FONT_SIZE`]..=[`MAX_EDITOR_FONT_SIZE`].
#[serde(default = "default_editor_font_size")]
pub editor_font_size: i32,
}

impl Default for UiSettings {
Expand All @@ -89,6 +100,8 @@ impl Default for UiSettings {
large_file_disable_smart_highlight: DEFAULT_LARGE_FILE_DISABLE_SMART_HIGHLIGHT,
recent_files: Vec::new(),
zoom_level: DEFAULT_ZOOM_LEVEL,
editor_font_name: DEFAULT_EDITOR_FONT_NAME.to_string(),
editor_font_size: DEFAULT_EDITOR_FONT_SIZE,
}
}
}
Expand Down Expand Up @@ -121,6 +134,10 @@ struct UiSettingsWire {
recent_files: Vec<String>,
#[serde(default)]
zoom_level: i32,
#[serde(default = "default_editor_font_name")]
editor_font_name: String,
#[serde(default = "default_editor_font_size")]
editor_font_size: i32,
}

impl From<UiSettingsWire> for UiSettings {
Expand All @@ -143,6 +160,8 @@ impl From<UiSettingsWire> for UiSettings {
.unwrap_or(DEFAULT_LARGE_FILE_DISABLE_SMART_HIGHLIGHT),
recent_files: value.recent_files,
zoom_level: value.zoom_level,
editor_font_name: value.editor_font_name,
editor_font_size: value.editor_font_size,
}
}
}
Expand Down Expand Up @@ -174,6 +193,12 @@ impl UiSettings {
.clamp(MIN_LARGE_FILE_THRESHOLD_MB, MAX_LARGE_FILE_THRESHOLD_MB);
self.recent_files.truncate(MAX_RECENT_FILES);
self.zoom_level = self.zoom_level.clamp(MIN_ZOOM_LEVEL, MAX_ZOOM_LEVEL);
if self.editor_font_name.trim().is_empty() {
self.editor_font_name = DEFAULT_EDITOR_FONT_NAME.to_string();
}
self.editor_font_size = self
.editor_font_size
.clamp(MIN_EDITOR_FONT_SIZE, MAX_EDITOR_FONT_SIZE);
self
}
}
Expand Down Expand Up @@ -222,6 +247,14 @@ fn default_editor_dark() -> bool {
DEFAULT_EDITOR_DARK
}

fn default_editor_font_name() -> String {
DEFAULT_EDITOR_FONT_NAME.to_string()
}

fn default_editor_font_size() -> i32 {
DEFAULT_EDITOR_FONT_SIZE
}

fn default_smart_highlight_match_case() -> bool {
DEFAULT_SMART_HIGHLIGHT_MATCH_CASE
}
Expand Down Expand Up @@ -351,6 +384,8 @@ mod tests {
large_file_disable_smart_highlight: true,
recent_files: vec!["C:\\a.txt".to_string(), "C:\\b.md".to_string()],
zoom_level: 3,
editor_font_name: "Consolas".to_string(),
editor_font_size: 11,
};
let json = serde_json::to_string_pretty(&settings).unwrap();
assert!(json.contains("\"tab_placement\": \"right\""));
Expand Down
21 changes: 16 additions & 5 deletions src/editor/scintilla.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const SCI_SETCODEPAGE: u32 = 2037;
const SCI_SETTEXT: u32 = 2181;
const SCI_GETTEXT: u32 = 2182;
const SCI_INSERTTEXT: u32 = 2003;
const SCI_REPLACESEL: u32 = 2170;
const SCI_GETLENGTH: u32 = 2006;
const SCI_GETCHARAT: u32 = 2007;
const SCI_GETCURRENTPOS: u32 = 2008;
Expand Down Expand Up @@ -607,8 +608,8 @@ pub fn create_window(parent: HWND, instance: HINSTANCE) -> Result<HWND> {
Ok(hwnd)
}

pub fn apply_lexer(hwnd: HWND, lexer: LexerKind, dark: bool) {
apply_base_theme(hwnd, dark);
pub fn apply_lexer(hwnd: HWND, lexer: LexerKind, dark: bool, font_name: &str, font_size: i32) {
apply_base_theme(hwnd, dark, font_name, font_size);
set_lexer_by_name(hwnd, lexer_name(lexer));
clear_keywords(hwnd);
apply_fold_properties(hwnd);
Expand Down Expand Up @@ -673,6 +674,16 @@ pub fn insert_text(hwnd: HWND, pos: usize, text: &str) {
send_message(hwnd, SCI_INSERTTEXT, pos, text.as_ptr() as isize);
}

/// Replaces the current selection (or inserts at the caret if the selection
/// is empty) with `text`, then leaves the caret positioned after it — the
/// same behavior as typing or pasting.
pub fn replace_selection(hwnd: HWND, text: &str) {
let Ok(text) = CString::new(text) else {
return;
};
send_message(hwnd, SCI_REPLACESEL, 0, text.as_ptr() as isize);
}

/// The newline sequence matching the document's current EOL mode.
pub fn eol_string(hwnd: HWND) -> &'static str {
match get_eol_mode(hwnd) {
Expand Down Expand Up @@ -968,7 +979,7 @@ fn lexer_name(lexer: LexerKind) -> &'static str {
}
}

fn apply_base_theme(hwnd: HWND, dark: bool) {
fn apply_base_theme(hwnd: HWND, dark: bool, font_name: &str, font_size: i32) {
let (fore, back, sel_back, caret, caret_line) = if dark {
(
COLOR_DARK_FORE,
Expand All @@ -988,8 +999,8 @@ fn apply_base_theme(hwnd: HWND, dark: bool) {
};
set_style_fore(hwnd, STYLE_DEFAULT, fore);
set_style_back(hwnd, STYLE_DEFAULT, back);
set_style_size(hwnd, STYLE_DEFAULT, 11);
set_style_font(hwnd, STYLE_DEFAULT, "Consolas");
set_style_size(hwnd, STYLE_DEFAULT, font_size.max(1) as usize);
set_style_font(hwnd, STYLE_DEFAULT, font_name);
send_message(hwnd, SCI_STYLECLEARALL, 0, 0);
send_message(hwnd, SCI_SETSELFORE, 1, fore as isize);
send_message(hwnd, SCI_SETSELBACK, 1, sel_back as isize);
Expand Down
Loading