From 59c08a6353f46de3e4e73a59617313bb2b68d618 Mon Sep 17 00:00:00 2001 From: Leonard Hecker Date: Mon, 25 Aug 2025 16:16:38 +0200 Subject: [PATCH 1/5] Move build.rs into its own directory --- Cargo.toml | 1 + build.rs | 315 ----------------------------------------------- build/helpers.rs | 11 ++ build/i18n.rs | 201 ++++++++++++++++++++++++++++++ build/main.rs | 123 ++++++++++++++++++ 5 files changed, 336 insertions(+), 315 deletions(-) delete mode 100644 build.rs create mode 100644 build/helpers.rs create mode 100644 build/i18n.rs create mode 100644 build/main.rs diff --git a/Cargo.toml b/Cargo.toml index ac4026bc4cd..792aa41d4fa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ repository = "https://github.com/microsoft/edit" homepage = "https://github.com/microsoft/edit" license = "MIT" categories = ["text-editors"] +build = "build/main.rs" [[bench]] name = "lib" diff --git a/build.rs b/build.rs deleted file mode 100644 index 2034ff83616..00000000000 --- a/build.rs +++ /dev/null @@ -1,315 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -#![allow(irrefutable_let_patterns)] - -use std::collections::{BTreeMap, HashMap, HashSet}; -use std::env::VarError; -use std::io::Write as _; - -#[derive(Clone, Copy, PartialEq, Eq)] -enum TargetOs { - Windows, - MacOS, - Unix, -} - -fn main() { - let target_os = match env_opt("CARGO_CFG_TARGET_OS").as_str() { - "windows" => TargetOs::Windows, - "macos" | "ios" => TargetOs::MacOS, - _ => TargetOs::Unix, - }; - - compile_i18n(); - configure_icu(target_os); - #[cfg(windows)] - configure_windows_binary(target_os); -} - -fn compile_i18n() { - const PATH: &str = "i18n/edit.toml"; - - let i18n = std::fs::read_to_string(PATH).unwrap(); - let i18n = toml_span::parse(&i18n).expect("Failed to parse i18n file"); - let root = i18n.as_table().unwrap(); - let mut languages = Vec::new(); - let mut aliases = Vec::new(); - let mut translations: BTreeMap> = BTreeMap::new(); - - for (k, v) in root.iter() { - match &k.name[..] { - "__default__" => { - const ERROR: &str = "i18n: __default__ must be [str]"; - languages = Vec::from_iter( - v.as_array() - .expect(ERROR) - .iter() - .map(|lang| lang.as_str().expect(ERROR).to_string()), - ); - } - "__alias__" => { - const ERROR: &str = "i18n: __alias__ must be str->str"; - aliases.extend(v.as_table().expect(ERROR).iter().map(|(alias, lang)| { - (alias.to_string(), lang.as_str().expect(ERROR).to_string()) - })); - } - _ => { - const ERROR: &str = "i18n: LocId must be str->str"; - translations.insert( - k.name.to_string(), - HashMap::from_iter( - v.as_table().expect(ERROR).iter().map(|(k, v)| { - (k.name.to_string(), v.as_str().expect(ERROR).to_string()) - }), - ), - ); - } - } - } - - // Use EDIT_CFG_LANGUAGES for the language list if it is set. - if let cfg_languages = env_opt("EDIT_CFG_LANGUAGES") - && !cfg_languages.is_empty() - { - languages = cfg_languages.split(',').map(|lang| lang.to_string()).collect(); - } - - // Ensure English as the fallback language is always present. - if !languages.iter().any(|l| l == "en") { - languages.push("en".to_string()); - } - - // Normalize language tags for use in source code (i.e. no "-"). - for lang in &mut languages { - if lang.is_empty() { - panic!("i18n: empty language tag"); - } - for c in unsafe { lang.as_bytes_mut() } { - *c = match *c { - b'A'..=b'Z' | b'a'..=b'z' => c.to_ascii_lowercase(), - b'-' => b'_', - b'_' => b'_', - _ => panic!("i18n: language tag \"{lang}\" must be [a-zA-Z_-]"), - } - } - } - - // * Validate that there are no duplicate language tags. - // * Validate that all language tags are valid. - // * Merge the aliases into the languages list. - let mut languages_with_aliases: Vec<_>; - { - let mut specified = HashSet::new(); - for lang in &languages { - if !specified.insert(lang.as_str()) { - panic!("i18n: duplicate language tag \"{lang}\""); - } - } - - let mut available = HashSet::new(); - for v in translations.values() { - for lang in v.keys() { - available.insert(lang.as_str()); - } - } - - let mut invalid = Vec::new(); - for lang in &languages { - if !available.contains(lang.as_str()) { - invalid.push(lang.as_str()); - } - } - if !invalid.is_empty() { - panic!("i18n: invalid language tags {invalid:?}"); - } - - languages_with_aliases = languages.iter().map(|l| (l.clone(), l.clone())).collect(); - for (alias, lang) in aliases { - if specified.contains(lang.as_str()) && !specified.contains(alias.as_str()) { - languages_with_aliases.push((alias, lang)); - } - } - } - - // Sort languages by: - // - "en" first, because it'll map to `LangId::en == 0`, which is the default. - // - then alphabetically - // - but tags with subtags (e.g. "zh_hans") before those without (e.g. "zh"). - { - fn sort(a: &String, b: &String) -> std::cmp::Ordering { - match (a == "en", b == "en") { - (true, false) => std::cmp::Ordering::Less, - (false, true) => std::cmp::Ordering::Greater, - _ => { - let (a0, a1) = a.split_once('_').unwrap_or((a, "xxxxxx")); - let (b0, b1) = b.split_once('_').unwrap_or((b, "xxxxxx")); - match a0.cmp(b0) { - std::cmp::Ordering::Equal => a1.cmp(b1), - ord => ord, - } - } - } - } - languages.sort_unstable_by(sort); - languages_with_aliases.sort_unstable_by(|a, b| sort(&a.0, &b.0)); - } - - // Generate the source code for the i18n data. - { - let out_dir = env_opt("OUT_DIR"); - let mut out = std::fs::File::create(format!("{out_dir}/i18n_edit.rs")).unwrap(); - let mut writer = std::io::BufWriter::new(&mut out); - - _ = write!( - writer, - "// This file is generated by build.rs. Do not edit it manually.\n\ - \n\ - #[derive(Clone, Copy, PartialEq, Eq)]\n\ - pub enum LocId {{\n", - ); - - for (k, _) in translations.iter() { - _ = writeln!(writer, " {k},"); - } - - _ = write!( - writer, - "}}\n\ - \n\ - #[allow(non_camel_case_types)]\n\ - #[derive(Clone, Copy, PartialEq, Eq)]\n\ - pub enum LangId {{\n", - ); - - for lang in &languages { - _ = writeln!(writer, " {lang},"); - } - - _ = write!( - writer, - "}}\n\ - \n\ - const LANGUAGES: &[(&str, LangId)] = &[\n" - ); - - for (alias, lang) in &languages_with_aliases { - _ = writeln!(writer, " ({alias:?}, LangId::{lang}),"); - } - - _ = write!( - writer, - "];\n\ - \n\ - const TRANSLATIONS: [[&str; {}]; {}] = [\n", - translations.len(), - languages.len(), - ); - - for lang in &languages { - _ = writeln!(writer, " ["); - for (_, v) in translations.iter() { - const DEFAULT: &String = &String::new(); - let v = v.get(lang).or_else(|| v.get("en")).unwrap_or(DEFAULT); - _ = writeln!(writer, " {v:?},"); - } - _ = writeln!(writer, " ],"); - } - - _ = writeln!(writer, "];"); - } - - println!("cargo::rerun-if-env-changed=EDIT_CFG_LANGUAGES"); - println!("cargo::rerun-if-changed={PATH}"); -} - -fn configure_icu(target_os: TargetOs) { - let icuuc_soname = env_opt("EDIT_CFG_ICUUC_SONAME"); - let icui18n_soname = env_opt("EDIT_CFG_ICUI18N_SONAME"); - let cpp_exports = env_opt("EDIT_CFG_ICU_CPP_EXPORTS"); - let renaming_version = env_opt("EDIT_CFG_ICU_RENAMING_VERSION"); - let renaming_auto_detect = env_opt("EDIT_CFG_ICU_RENAMING_AUTO_DETECT"); - - // If none of the `EDIT_CFG_ICU*` environment variables are set, - // we default to enabling `EDIT_CFG_ICU_RENAMING_AUTO_DETECT` on UNIX. - // This slightly improves portability at least in the cases where the SONAMEs match our defaults. - let renaming_auto_detect = if !renaming_auto_detect.is_empty() { - renaming_auto_detect.parse::().unwrap() - } else { - target_os == TargetOs::Unix - && icuuc_soname.is_empty() - && icui18n_soname.is_empty() - && cpp_exports.is_empty() - && renaming_version.is_empty() - }; - if renaming_auto_detect && !renaming_version.is_empty() { - // It makes no sense to specify an explicit version and also ask for auto-detection. - panic!( - "Either `EDIT_CFG_ICU_RENAMING_AUTO_DETECT` or `EDIT_CFG_ICU_RENAMING_VERSION` must be set, but not both" - ); - } - - let icuuc_soname = if !icuuc_soname.is_empty() { - &icuuc_soname - } else { - match target_os { - TargetOs::Windows => "icuuc.dll", - TargetOs::MacOS => "libicucore.dylib", - TargetOs::Unix => "libicuuc.so", - } - }; - let icui18n_soname = if !icui18n_soname.is_empty() { - &icui18n_soname - } else { - match target_os { - TargetOs::Windows => "icuin.dll", - TargetOs::MacOS => "libicucore.dylib", - TargetOs::Unix => "libicui18n.so", - } - }; - let icu_export_prefix = - if !cpp_exports.is_empty() && cpp_exports.parse::().unwrap() { "_" } else { "" }; - let icu_export_suffix = - if !renaming_version.is_empty() { format!("_{renaming_version}") } else { String::new() }; - - println!("cargo::rerun-if-env-changed=EDIT_CFG_ICUUC_SONAME"); - println!("cargo::rustc-env=EDIT_CFG_ICUUC_SONAME={icuuc_soname}"); - println!("cargo::rerun-if-env-changed=EDIT_CFG_ICUI18N_SONAME"); - println!("cargo::rustc-env=EDIT_CFG_ICUI18N_SONAME={icui18n_soname}"); - println!("cargo::rerun-if-env-changed=EDIT_CFG_ICU_EXPORT_PREFIX"); - println!("cargo::rustc-env=EDIT_CFG_ICU_EXPORT_PREFIX={icu_export_prefix}"); - println!("cargo::rerun-if-env-changed=EDIT_CFG_ICU_EXPORT_SUFFIX"); - println!("cargo::rustc-env=EDIT_CFG_ICU_EXPORT_SUFFIX={icu_export_suffix}"); - println!("cargo::rerun-if-env-changed=EDIT_CFG_ICU_RENAMING_AUTO_DETECT"); - println!("cargo::rustc-check-cfg=cfg(edit_icu_renaming_auto_detect)"); - if renaming_auto_detect { - println!("cargo::rustc-cfg=edit_icu_renaming_auto_detect"); - } -} - -#[cfg(windows)] -fn configure_windows_binary(target_os: TargetOs) { - if target_os != TargetOs::Windows { - return; - } - - const PATH: &str = "src/bin/edit/edit.exe.manifest"; - println!("cargo::rerun-if-changed={PATH}"); - winresource::WindowsResource::new() - .set_manifest_file(PATH) - .set("FileDescription", "Microsoft Edit") - .set("LegalCopyright", "© Microsoft Corporation. All rights reserved.") - .set_icon("assets/edit.ico") - .compile() - .unwrap(); -} - -fn env_opt(name: &str) -> String { - match std::env::var(name) { - Ok(value) => value, - Err(VarError::NotPresent) => String::new(), - Err(VarError::NotUnicode(_)) => { - panic!("Environment variable `{name}` is not valid Unicode") - } - } -} diff --git a/build/helpers.rs b/build/helpers.rs new file mode 100644 index 00000000000..7453c34a0a9 --- /dev/null +++ b/build/helpers.rs @@ -0,0 +1,11 @@ +use std::env::VarError; + +pub fn env_opt(name: &str) -> String { + match std::env::var(name) { + Ok(value) => value, + Err(VarError::NotPresent) => String::new(), + Err(VarError::NotUnicode(_)) => { + panic!("Environment variable `{name}` is not valid Unicode") + } + } +} diff --git a/build/i18n.rs b/build/i18n.rs new file mode 100644 index 00000000000..4089902e313 --- /dev/null +++ b/build/i18n.rs @@ -0,0 +1,201 @@ +use std::collections::{BTreeMap, HashMap, HashSet}; +use std::fmt::Write as _; + +use crate::helpers::env_opt; + +pub fn generate(definitions: &str) -> String { + let i18n = toml_span::parse(definitions).expect("Failed to parse i18n file"); + let root = i18n.as_table().unwrap(); + let mut languages = Vec::new(); + let mut aliases = Vec::new(); + let mut translations: BTreeMap> = BTreeMap::new(); + + for (k, v) in root.iter() { + match &k.name[..] { + "__default__" => { + const ERROR: &str = "i18n: __default__ must be [str]"; + languages = Vec::from_iter( + v.as_array() + .expect(ERROR) + .iter() + .map(|lang| lang.as_str().expect(ERROR).to_string()), + ); + } + "__alias__" => { + const ERROR: &str = "i18n: __alias__ must be str->str"; + aliases.extend(v.as_table().expect(ERROR).iter().map(|(alias, lang)| { + (alias.to_string(), lang.as_str().expect(ERROR).to_string()) + })); + } + _ => { + const ERROR: &str = "i18n: LocId must be str->str"; + translations.insert( + k.name.to_string(), + HashMap::from_iter( + v.as_table().expect(ERROR).iter().map(|(k, v)| { + (k.name.to_string(), v.as_str().expect(ERROR).to_string()) + }), + ), + ); + } + } + } + + // Use EDIT_CFG_LANGUAGES for the language list if it is set. + if let cfg_languages = env_opt("EDIT_CFG_LANGUAGES") + && !cfg_languages.is_empty() + { + languages = cfg_languages.split(',').map(|lang| lang.to_string()).collect(); + } + + // Ensure English as the fallback language is always present. + if !languages.iter().any(|l| l == "en") { + languages.push("en".to_string()); + } + + // Normalize language tags for use in source code (i.e. no "-"). + for lang in &mut languages { + if lang.is_empty() { + panic!("i18n: empty language tag"); + } + for c in unsafe { lang.as_bytes_mut() } { + *c = match *c { + b'A'..=b'Z' | b'a'..=b'z' => c.to_ascii_lowercase(), + b'-' => b'_', + b'_' => b'_', + _ => panic!("i18n: language tag \"{lang}\" must be [a-zA-Z_-]"), + } + } + } + + // * Validate that there are no duplicate language tags. + // * Validate that all language tags are valid. + // * Merge the aliases into the languages list. + let mut languages_with_aliases: Vec<_>; + { + let mut specified = HashSet::new(); + for lang in &languages { + if !specified.insert(lang.as_str()) { + panic!("i18n: duplicate language tag \"{lang}\""); + } + } + + let mut available = HashSet::new(); + for v in translations.values() { + for lang in v.keys() { + available.insert(lang.as_str()); + } + } + + let mut invalid = Vec::new(); + for lang in &languages { + if !available.contains(lang.as_str()) { + invalid.push(lang.as_str()); + } + } + if !invalid.is_empty() { + panic!("i18n: invalid language tags {invalid:?}"); + } + + languages_with_aliases = languages.iter().map(|l| (l.clone(), l.clone())).collect(); + for (alias, lang) in aliases { + if specified.contains(lang.as_str()) && !specified.contains(alias.as_str()) { + languages_with_aliases.push((alias, lang)); + } + } + } + + // Sort languages by: + // - "en" first, because it'll map to `LangId::en == 0`, which is the default. + // - then alphabetically + // - but tags with subtags (e.g. "zh_hans") before those without (e.g. "zh"). + { + fn sort(a: &String, b: &String) -> std::cmp::Ordering { + match (a == "en", b == "en") { + (true, false) => std::cmp::Ordering::Less, + (false, true) => std::cmp::Ordering::Greater, + _ => { + let (a0, a1) = a.split_once('_').unwrap_or((a, "xxxxxx")); + let (b0, b1) = b.split_once('_').unwrap_or((b, "xxxxxx")); + match a0.cmp(b0) { + std::cmp::Ordering::Equal => a1.cmp(b1), + ord => ord, + } + } + } + } + languages.sort_unstable_by(sort); + languages_with_aliases.sort_unstable_by(|a, b| sort(&a.0, &b.0)); + } + + let mut out = String::new(); + + // Generate the source code for the i18n data. + { + _ = write!( + out, + "\ +// This file is generated by build.rs. Do not edit it manually. + +#[derive(Clone, Copy, PartialEq, Eq)] +pub enum LocId {{", + ); + + for (k, _) in translations.iter() { + _ = writeln!(out, " {k},"); + } + + _ = write!( + out, + "\ +}} + +#[allow(non_camel_case_types)] +#[derive(Clone, Copy, PartialEq, Eq)] +pub enum LangId {{ +", + ); + + for lang in &languages { + _ = writeln!(out, " {lang},"); + } + + _ = write!( + out, + "\ +}} + +const LANGUAGES: &[(&str, LangId)] = &[ +" + ); + + for (alias, lang) in &languages_with_aliases { + _ = writeln!(out, " ({alias:?}, LangId::{lang}),"); + } + + _ = write!( + out, + "\ +]; + +const TRANSLATIONS: [[&str; {}]; {}] = [ +", + translations.len(), + languages.len(), + ); + + for lang in &languages { + _ = writeln!(out, " ["); + for (_, v) in translations.iter() { + const DEFAULT: &String = &String::new(); + let v = v.get(lang).or_else(|| v.get("en")).unwrap_or(DEFAULT); + _ = writeln!(out, " {v:?},"); + } + _ = writeln!(out, " ],"); + } + + _ = writeln!(out, "];"); + } + + out +} diff --git a/build/main.rs b/build/main.rs new file mode 100644 index 00000000000..fb1d8d157f9 --- /dev/null +++ b/build/main.rs @@ -0,0 +1,123 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#![allow(irrefutable_let_patterns)] + +use crate::helpers::env_opt; + +mod helpers; +mod i18n; + +#[derive(Clone, Copy, PartialEq, Eq)] +enum TargetOs { + Windows, + MacOS, + Unix, +} + +fn main() { + let target_os = match env_opt("CARGO_CFG_TARGET_OS").as_str() { + "windows" => TargetOs::Windows, + "macos" | "ios" => TargetOs::MacOS, + _ => TargetOs::Unix, + }; + + compile_i18n(); + configure_icu(target_os); + #[cfg(windows)] + configure_windows_binary(target_os); +} + +fn compile_i18n() { + const PATH: &str = "i18n/edit.toml"; + + let i18n = std::fs::read_to_string(PATH).unwrap(); + let contents = i18n::generate(&i18n); + let out_dir = env_opt("OUT_DIR"); + let path = format!("{out_dir}/i18n_edit.rs"); + std::fs::write(path, contents).unwrap(); + + println!("cargo::rerun-if-env-changed=EDIT_CFG_LANGUAGES"); + println!("cargo::rerun-if-changed={PATH}"); +} + +fn configure_icu(target_os: TargetOs) { + let icuuc_soname = env_opt("EDIT_CFG_ICUUC_SONAME"); + let icui18n_soname = env_opt("EDIT_CFG_ICUI18N_SONAME"); + let cpp_exports = env_opt("EDIT_CFG_ICU_CPP_EXPORTS"); + let renaming_version = env_opt("EDIT_CFG_ICU_RENAMING_VERSION"); + let renaming_auto_detect = env_opt("EDIT_CFG_ICU_RENAMING_AUTO_DETECT"); + + // If none of the `EDIT_CFG_ICU*` environment variables are set, + // we default to enabling `EDIT_CFG_ICU_RENAMING_AUTO_DETECT` on UNIX. + // This slightly improves portability at least in the cases where the SONAMEs match our defaults. + let renaming_auto_detect = if !renaming_auto_detect.is_empty() { + renaming_auto_detect.parse::().unwrap() + } else { + target_os == TargetOs::Unix + && icuuc_soname.is_empty() + && icui18n_soname.is_empty() + && cpp_exports.is_empty() + && renaming_version.is_empty() + }; + if renaming_auto_detect && !renaming_version.is_empty() { + // It makes no sense to specify an explicit version and also ask for auto-detection. + panic!( + "Either `EDIT_CFG_ICU_RENAMING_AUTO_DETECT` or `EDIT_CFG_ICU_RENAMING_VERSION` must be set, but not both" + ); + } + + let icuuc_soname = if !icuuc_soname.is_empty() { + &icuuc_soname + } else { + match target_os { + TargetOs::Windows => "icuuc.dll", + TargetOs::MacOS => "libicucore.dylib", + TargetOs::Unix => "libicuuc.so", + } + }; + let icui18n_soname = if !icui18n_soname.is_empty() { + &icui18n_soname + } else { + match target_os { + TargetOs::Windows => "icuin.dll", + TargetOs::MacOS => "libicucore.dylib", + TargetOs::Unix => "libicui18n.so", + } + }; + let icu_export_prefix = + if !cpp_exports.is_empty() && cpp_exports.parse::().unwrap() { "_" } else { "" }; + let icu_export_suffix = + if !renaming_version.is_empty() { format!("_{renaming_version}") } else { String::new() }; + + println!("cargo::rerun-if-env-changed=EDIT_CFG_ICUUC_SONAME"); + println!("cargo::rustc-env=EDIT_CFG_ICUUC_SONAME={icuuc_soname}"); + println!("cargo::rerun-if-env-changed=EDIT_CFG_ICUI18N_SONAME"); + println!("cargo::rustc-env=EDIT_CFG_ICUI18N_SONAME={icui18n_soname}"); + println!("cargo::rerun-if-env-changed=EDIT_CFG_ICU_EXPORT_PREFIX"); + println!("cargo::rustc-env=EDIT_CFG_ICU_EXPORT_PREFIX={icu_export_prefix}"); + println!("cargo::rerun-if-env-changed=EDIT_CFG_ICU_EXPORT_SUFFIX"); + println!("cargo::rustc-env=EDIT_CFG_ICU_EXPORT_SUFFIX={icu_export_suffix}"); + println!("cargo::rerun-if-env-changed=EDIT_CFG_ICU_RENAMING_AUTO_DETECT"); + println!("cargo::rustc-check-cfg=cfg(edit_icu_renaming_auto_detect)"); + if renaming_auto_detect { + println!("cargo::rustc-cfg=edit_icu_renaming_auto_detect"); + } +} + +#[cfg(windows)] +fn configure_windows_binary(target_os: TargetOs) { + if target_os != TargetOs::Windows { + return; + } + + const PATH: &str = "src/bin/edit/edit.exe.manifest"; + println!("cargo::rerun-if-changed={PATH}"); + winresource::WindowsResource::new() + .set_manifest_file(PATH) + .set("FileDescription", "Microsoft Edit") + .set("LegalCopyright", "© Microsoft Corporation. All rights reserved.") + .set_icon("assets/edit.ico") + .compile() + .unwrap(); +} From 3d8e5d973d5828a6dc5fcafd55b592cb9c188ea2 Mon Sep 17 00:00:00 2001 From: Leonard Hecker Date: Mon, 25 Aug 2025 16:28:09 +0200 Subject: [PATCH 2/5] A first draft for simple syntax highlighting --- .vscode/launch.json | 6 +- Cargo.lock | 116 ++- Cargo.toml | 3 +- assets/highlighting-tests/COMMIT_EDITMSG | 62 ++ assets/highlighting-tests/bash.sh | 71 ++ assets/highlighting-tests/batch.bat | 41 + assets/highlighting-tests/diff.diff | 142 +++ assets/highlighting-tests/git-rebase-todo | 54 + assets/highlighting-tests/json.json | 26 + assets/highlighting-tests/powershell.ps1 | 78 ++ assets/highlighting-tests/yaml.yml | 41 + benches/lib.rs | 28 +- build/lsh/definitions.rs | 432 ++++++++ build/lsh/handles.rs | 111 ++ build/lsh/mod.rs | 234 +++++ build/lsh/transformer.rs | 1151 +++++++++++++++++++++ build/main.rs | 9 + i18n/edit.toml | 26 + src/bin/edit/documents.rs | 30 +- src/bin/edit/draw_statusbar.rs | 64 +- src/bin/edit/main.rs | 3 + src/bin/edit/state.rs | 4 + src/buffer/line_cache.rs | 116 --- src/buffer/mod.rs | 83 +- src/framebuffer.rs | 6 + src/helpers.rs | 2 +- src/lib.rs | 1 + src/lsh/cache.rs | 82 ++ src/lsh/definitions.rs | 1 + src/lsh/highlighter.rs | 343 ++++++ src/lsh/mod.rs | 8 + src/sys/windows.rs | 10 +- 32 files changed, 3190 insertions(+), 194 deletions(-) create mode 100644 assets/highlighting-tests/COMMIT_EDITMSG create mode 100644 assets/highlighting-tests/bash.sh create mode 100644 assets/highlighting-tests/batch.bat create mode 100644 assets/highlighting-tests/diff.diff create mode 100644 assets/highlighting-tests/git-rebase-todo create mode 100644 assets/highlighting-tests/json.json create mode 100644 assets/highlighting-tests/powershell.ps1 create mode 100644 assets/highlighting-tests/yaml.yml create mode 100644 build/lsh/definitions.rs create mode 100644 build/lsh/handles.rs create mode 100644 build/lsh/mod.rs create mode 100644 build/lsh/transformer.rs delete mode 100644 src/buffer/line_cache.rs create mode 100644 src/lsh/cache.rs create mode 100644 src/lsh/definitions.rs create mode 100644 src/lsh/highlighter.rs create mode 100644 src/lsh/mod.rs diff --git a/.vscode/launch.json b/.vscode/launch.json index d11a903eace..240860d257e 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -10,7 +10,7 @@ "program": "${workspaceFolder}/target/debug/edit", "cwd": "${workspaceFolder}", "args": [ - "${workspaceFolder}/src/bin/edit/main.rs" + "${workspaceFolder}/assets/highlighting-tests/COMMIT_EDITMSG" ], }, { @@ -21,7 +21,7 @@ "program": "${workspaceFolder}/target/debug/edit", "cwd": "${workspaceFolder}", "args": [ - "${workspaceFolder}/src/bin/edit/main.rs" + "${workspaceFolder}/assets/highlighting-tests/COMMIT_EDITMSG" ], }, { @@ -32,7 +32,7 @@ "program": "${workspaceFolder}/target/debug/edit", "cwd": "${workspaceFolder}", "args": [ - "${workspaceFolder}/src/bin/edit/main.rs" + "${workspaceFolder}/assets/highlighting-tests/COMMIT_EDITMSG" ], } ] diff --git a/Cargo.lock b/Cargo.lock index b27fd66dea4..93a0ca39b73 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -31,9 +31,9 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "bitflags" -version = "2.9.1" +version = "2.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" +checksum = "34efbcccd345379ca2868b2b2c9d3782e9cc58ba87bc7d79d5b53d9c9ae6f25d" [[package]] name = "bumpalo" @@ -49,9 +49,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.2.30" +version = "1.2.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "deec109607ca693028562ed836a5f1c4b8bd77755c4e132fc5ce11b0b6211ae7" +checksum = "42bc4aea80032b7bf409b0bc7ccad88853858911b7713a8062fdc0623867bedc" dependencies = [ "jobserver", "libc", @@ -60,9 +60,9 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.1" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" [[package]] name = "ciborium" @@ -93,18 +93,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.42" +version = "4.5.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed87a9d530bb41a67537289bafcac159cb3ee28460e0a4571123d2a778a6a882" +checksum = "1fc0e74a703892159f5ae7d3aac52c8e6c392f5ae5f359c70b5881d60aaac318" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.5.42" +version = "4.5.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64f4f3f3c77c94aff3c7e9aac9a2ca1974a5adf392a8bb751e827d6d127ab966" +checksum = "b3e7f4214277f3c7aa526a59dd3fbe306a370daee1f8b7b8c987069cd8e888a8" dependencies = [ "anstyle", "clap_lex", @@ -186,6 +186,7 @@ version = "1.2.1" dependencies = [ "criterion", "libc", + "regex-syntax", "serde", "serde_json", "toml-span", @@ -239,9 +240,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jobserver" -version = "0.1.33" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" dependencies = [ "getrandom", "libc", @@ -259,9 +260,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.174" +version = "0.2.175" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" +checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" [[package]] name = "log" @@ -332,9 +333,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.95" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" dependencies = [ "unicode-ident", ] @@ -356,9 +357,9 @@ checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" [[package]] name = "rayon" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" dependencies = [ "either", "rayon-core", @@ -366,9 +367,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.12.1" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" dependencies = [ "crossbeam-deque", "crossbeam-utils", @@ -376,9 +377,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.11.1" +version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912" dependencies = [ "aho-corasick", "memchr", @@ -388,9 +389,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6" dependencies = [ "aho-corasick", "memchr", @@ -399,15 +400,15 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" [[package]] name = "rustversion" -version = "1.0.21" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "ryu" @@ -446,9 +447,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.141" +version = "1.0.143" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30b9eff21ebe718216c6ec64e1d9ac57087aad11efc64e32002bce4a0d4c03d3" +checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a" dependencies = [ "itoa", "memchr", @@ -470,9 +471,9 @@ checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "syn" -version = "2.0.104" +version = "2.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" dependencies = [ "proc-macro2", "quote", @@ -599,28 +600,35 @@ dependencies = [ [[package]] name = "winapi-util" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +checksum = "0978bf7171b3d90bac376700cb56d606feb40f251a475a5d6634613564460b22" dependencies = [ "windows-sys", ] +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + [[package]] name = "windows-sys" -version = "0.59.0" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ "windows-targets", ] [[package]] name = "windows-targets" -version = "0.52.6" +version = "0.53.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" dependencies = [ + "windows-link", "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", @@ -633,51 +641,51 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.6" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" [[package]] name = "windows_aarch64_msvc" -version = "0.52.6" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" [[package]] name = "windows_i686_gnu" -version = "0.52.6" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" [[package]] name = "windows_i686_gnullvm" -version = "0.52.6" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" [[package]] name = "windows_i686_msvc" -version = "0.52.6" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" [[package]] name = "windows_x86_64_gnu" -version = "0.52.6" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.6" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" [[package]] name = "windows_x86_64_msvc" -version = "0.52.6" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" [[package]] name = "winresource" diff --git a/Cargo.toml b/Cargo.toml index 792aa41d4fa..3aa761b4519 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,6 +40,7 @@ lto = "thin" # Similarly, speed up linking by a ton libc = "0.2" [build-dependencies] +regex-syntax = { version = "0.8", default-features = false } # The default toml crate bundles its dependencies with bad compile times. Thanks. # Thankfully toml-span exists. FWIW the alternative is yaml-rust (without the 2 suffix). toml-span = { version = "0.5", default-features = false } @@ -48,7 +49,7 @@ toml-span = { version = "0.5", default-features = false } winresource = { version = "0.1.22", default-features = false } [target.'cfg(windows)'.dependencies.windows-sys] -version = "0.59" +version = "0.60" features = [ "Win32_Globalization", "Win32_Security", diff --git a/assets/highlighting-tests/COMMIT_EDITMSG b/assets/highlighting-tests/COMMIT_EDITMSG new file mode 100644 index 00000000000..cfba35d08da --- /dev/null +++ b/assets/highlighting-tests/COMMIT_EDITMSG @@ -0,0 +1,62 @@ +lsh: flip legacy flag, add follow-up hook & diff test + +Refactors placeholder logic and introduces a lightweight follow-up hook. +Adds diff highlighting test and removes outdated asset to streamline visuals. + +# Please enter the commit message for your changes. Lines starting +# with '#' will be ignored, and an empty message aborts the commit. +# +# On branch foobar +# Your branch is up to date with 'origin/foobar'. +# +# Changes to be committed: +# renamed: foo.rs -> bar.rs +# modified: src/lsh/definitions.rs +# deleted: assets/old_logo.svg +# new file: baz.rs +# +# ------------------------ >8 ------------------------ +# Do not modify or remove the line above. +# Everything below it will be ignored. +diff --git a/src/lsh/definitions.rs b/src/lsh/definitions.rs +index a1b2c3d..d4c3b2a 100644 +--- a/src/lsh/definitions.rs ++++ b/src/lsh/definitions.rs +@@ -12,9 +12,11 @@ // context line 12 + // context line 13 +-// old placeholder logic A +-const LEGACY_FLAG: bool = true; +-// end legacy block ++// updated placeholder logic A ++const LEGACY_FLAG: bool = false; // flipped for test ++// added note: migration in progress ++// end legacy block + // context line 19 + // context line 20 +@@ -42,7 +44,12 @@ // context line 42 + // context line 43 +- do_placeholder_action(alpha, beta); ++ // Split actions for clarity ++ do_placeholder_prepare(alpha); ++ do_placeholder_action(alpha, beta); ++ if (enable_extra()) { ++ do_placeholder_followup(beta); ++ } + // context line 50 + // context line 51 + // context line 52 +@@ -90,6 +97,15 @@ // context line 90 + // context line 91 + // context line 92 ++/// Added lightweight fake helper ++fn enable_extra() -> bool { ++ // Pretend this consults a config value ++ true ++} ++ ++// Temporary debug instrumentation (to be removed) ++const _DEBUG_HOOK: &str = "lsh:extra"; ++ + // context line 93 + // context line 94 + // context line 95 diff --git a/assets/highlighting-tests/bash.sh b/assets/highlighting-tests/bash.sh new file mode 100644 index 00000000000..dfd5238724d --- /dev/null +++ b/assets/highlighting-tests/bash.sh @@ -0,0 +1,71 @@ +#!/usr/bin/env bash + +# This is a comment + +readonly VAR1="Hello" # String literal +VAR2=42 # Integer literal +VAR3=$((VAR2 + 8)) # Arithmetic expansion +VAR4=$(echo "World") # Command substitution + +function greet() { # Function definition + local name="$1" # Local variable, parameter expansion + echo "${VAR1}, $name! $VAR4" # String, parameter expansion, variable +} + +greet "User" # Function call, string literal + +if [[ $VAR2 -gt 40 && $VAR3 -eq 50 ]]; then # Conditional, test, operators + echo "Numbers are correct" # String literal +elif (( VAR2 < 40 )); then # Arithmetic test + echo 'VAR2 is less than 40' # Single-quoted string +else + echo "Other case" +fi + +for i in {1..3}; do # Brace expansion, for loop + echo "Loop $i" # String, variable +done + +case "$VAR4" in # Case statement + World) echo "It's World";; # Pattern, string + *) echo "Unknown";; # Wildcard +esac + +arr=(one two three) # Array +echo "${arr[1]}" # Array access + +declare -A assoc # Associative array +assoc[key]="value" +echo "${assoc[key]}" + +# Here document +cat < /dev/null + +# Background job +sleep 1 & + +# Arithmetic assignment +let VAR2+=1 + +# Process substitution +diff <(echo foo) <(echo bar) + +# Command grouping +{ echo "Group 1"; echo "Group 2"; } + +# Escaped characters +echo "A quote: \" and a backslash: \\" + +# End of file diff --git a/assets/highlighting-tests/batch.bat b/assets/highlighting-tests/batch.bat new file mode 100644 index 00000000000..962ef66007a --- /dev/null +++ b/assets/highlighting-tests/batch.bat @@ -0,0 +1,41 @@ +@echo off +REM --- String, Variable, Label, Command, Operator, Number, Delimiter, Comment --- + +:: Label +:Start + +:: Variable assignment and usage +set "VAR1=Hello" +set VAR2=World + +:: String with spaces and special characters +set "STR=Batch ^& CMD!" + +:: Arithmetic operation (number, operator) +set /a SUM=5+10 + +:: IF statement (keyword, operator, string, variable) +if "%VAR1%"=="Hello" ( + echo %VAR1%, %VAR2%! %STR% +) else ( + echo Not matched! +) + +:: FOR loop (keyword, variable, delimiter, string) +for %%F in (*.bat) do ( + echo Found file: %%F +) + +:: CALL command (keyword, label) +call :SubRoutine + +:: GOTO command (keyword, label) +goto :End + +:: Subroutine with parameter +:SubRoutine +echo In subroutine with SUM=%SUM% +goto :eof + +:End +REM End of script diff --git a/assets/highlighting-tests/diff.diff b/assets/highlighting-tests/diff.diff new file mode 100644 index 00000000000..8d033f94bfc --- /dev/null +++ b/assets/highlighting-tests/diff.diff @@ -0,0 +1,142 @@ +diff --git a/src/lsh/definitions.rs b/src/lsh/definitions.rs +index a1b2c3d..d4c3b2a 100644 +--- a/src/lsh/definitions.rs ++++ b/src/lsh/definitions.rs +@@ -12,9 +12,11 @@ // context line 12 + // context line 13 +-// old placeholder logic A +-const LEGACY_FLAG: bool = true; +-// end legacy block ++// updated placeholder logic A ++const LEGACY_FLAG: bool = false; // flipped for test ++// added note: migration in progress ++// end legacy block + // context line 19 + // context line 20 +@@ -42,7 +44,12 @@ // context line 42 + // context line 43 +- do_placeholder_action(alpha, beta); ++ // Split actions for clarity ++ do_placeholder_prepare(alpha); ++ do_placeholder_action(alpha, beta); ++ if (enable_extra()) { ++ do_placeholder_followup(beta); ++ } + // context line 50 + // context line 51 + // context line 52 +@@ -90,6 +97,15 @@ // context line 90 + // context line 91 + // context line 92 ++/// Added lightweight fake helper ++fn enable_extra() -> bool { ++ // Pretend this consults a config value ++ true ++} ++ ++// Temporary debug instrumentation (to be removed) ++const _DEBUG_HOOK: &str = "lsh:extra"; ++ + // context line 93 + // context line 94 + // context line 95 + +diff --git a/src/tui.rs b/src/tui.rs +index 1122334..5566778 100644 +--- a/src/tui.rs ++++ b/src/tui.rs +@@ -5,8 +5,13 @@ // context line 5 + // context line 6 + // context line 7 +-// previous rendering stub +-render_placeholder(frame); ++// refined rendering sequence ++begin_frame(frame); ++render_header(frame); ++render_body(frame); ++render_footer(frame); ++end_frame(frame); ++ + // context line 14 + // context line 15 + // context line 16 + +diff --git a/README.md b/README.md +index 9aa9aa9..1bb1bb1 100644 +--- a/README.md ++++ b/README.md +@@ -1,6 +1,11 @@ + # Project Title +-Some brief description here. ++Some brief description here (updated). ++ ++Experimental notes: ++- Added fake diff example ++- Demonstrates multi-hunk & multi-file patch ++ + ## Usage + Run the binary as needed. + +diff --git a/Cargo.toml b/Cargo.toml +index cafe123..fade321 100644 +--- a/Cargo.toml ++++ b/Cargo.toml +@@ -8,7 +8,10 @@ edition = "2021" + # context + [features] +-default = [] ++default = ["experimental-preview"] ++experimental-preview = [] ++ ++# NOTE: Above feature is placeholder & fake + + [dependencies] + # context +@@ -20,6 +23,7 @@ anyhow = "1" + # context + # instrumentation (fake addition) + tracing = "0.1" ++tracing-subscriber = "0.3" + +diff --git a/src/feature/experimental.rs b/src/feature/experimental.rs +new file mode 100644 +index 0000000..abc1234 +--- /dev/null ++++ b/src/feature/experimental.rs +@@ -0,0 +1,24 @@ ++//! Placeholder experimental module (fake content). ++//! This file exists only to demonstrate a multi-file diff. ++#![allow(dead_code)] ++ ++pub struct ExperimentalToggle { ++ enabled: bool, ++} ++ ++impl ExperimentalToggle { ++ pub fn new() -> Self { ++ Self { enabled: true } ++ } ++ pub fn enabled(&self) -> bool { ++ self.enabled ++ } ++} ++ ++pub fn run_experimental_path() { ++ if ExperimentalToggle::new().enabled() { ++ // Fake behavior ++ eprintln!("(fake) running experimental path"); ++ } ++} ++ + +diff --git a/assets/old_logo.svg b/assets/old_logo.svg +deleted file mode 100644 +index 55aa55a..0000000 +--- a/assets/old_logo.svg ++++ /dev/null +@@ -1,5 +0,0 @@ +- +- +- +- X +- diff --git a/assets/highlighting-tests/git-rebase-todo b/assets/highlighting-tests/git-rebase-todo new file mode 100644 index 00000000000..d051d122292 --- /dev/null +++ b/assets/highlighting-tests/git-rebase-todo @@ -0,0 +1,54 @@ +pick 3f9d2ab # chore(ci): add initial pipeline +pick e12c0ff # feat(io): introduce streaming reader +reword 7ac14d0 feat(io): add zero-copy buffered writer +edit 4d92b67 fix(io): handle partial UTF-8 sequences at buffer boundary +pick 8bb3a21 docs: expand README performance section +squash 1c02f55 docs: tidy wording in performance section +pick 54ae91b feat(cli): add --color=auto detection +fixup 0b77c3e feat(cli): typo in help text +fixup -c 2f4e8ab feat(cli): adjust arg parsing error message +pick 6d8e5f1 refactor(core): split large module into submodules +break +pick a41e9d3 test(core): add regression tests for issue #410 +exec cargo test --package edit --lib --quiet +pick c3bb921 perf(render): SIMD accelerate line diffing +drop 91d0f2e debug(render): temporary logging (to be dropped) +label pre-merge-split +pick d2f7ac4 feat(ui): add mouse wheel smooth scrolling +pick f1a4bd9 feat(ui): add high-DPI awareness +label post-ui +update-ref refs/heads/feature/ui-stack-post +reset pre-merge-split +merge -C 5ab77e3 post-ui # Merge UI feature stack +pick d8c4b91 build: bump version to 0.9.0 + +# Rebase 3f9d2ab..d8c4b91 onto d8c4b91 (18 commands) +# +# Commands: +# p, pick = use commit +# r, reword = use commit, but edit the commit message +# e, edit = use commit, but stop for amending +# s, squash = use commit, but meld into previous commit +# f, fixup [-C | -c] = like "squash" but keep only the previous +# commit's log message, unless -C is used, in which case +# keep only this commit's message; -c is same as -C but +# opens the editor +# x, exec = run command (the rest of the line) using shell +# b, break = stop here (continue rebase later with 'git rebase --continue') +# d, drop = remove commit +# l, label