From 3be8e29b1e817b422b117c66d0e50ecdb3be7b87 Mon Sep 17 00:00:00 2001 From: naaiyy Date: Tue, 17 Feb 2026 02:43:54 +0100 Subject: [PATCH 1/4] ci: Add CI workflow and CODEOWNERS Add GitHub Actions CI with cargo fmt check, clippy, and tests on macOS. Gate job `ci_pass` aggregates all checks. Add CODEOWNERS with @naaiyy as global owner. Co-Authored-By: Claude Opus 4.6 --- .github/CODEOWNERS | 1 + .github/workflows/ci.yml | 49 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 .github/CODEOWNERS create mode 100644 .github/workflows/ci.yml diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..04af23f --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @naaiyy diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..e9acaea --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,49 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + branches: [main] + +env: + CARGO_TERM_COLOR: always + +jobs: + check_style: + name: Check style + runs-on: macos-latest + steps: + - uses: actions/checkout@v4 + - name: Check formatting + run: cargo fmt --all --check + + clippy: + name: Clippy + runs-on: macos-latest + steps: + - uses: actions/checkout@v4 + - name: Run clippy + run: cargo clippy --workspace --all-targets -- -D warnings + + tests: + name: Tests + runs-on: macos-latest + steps: + - uses: actions/checkout@v4 + - name: Run tests + run: cargo test --workspace --no-fail-fast + + ci_pass: + name: CI Pass + runs-on: ubuntu-latest + needs: [check_style, clippy, tests] + if: always() + steps: + - name: Check results + run: | + if [[ "${{ needs.check_style.result }}" == "failure" || "${{ needs.clippy.result }}" == "failure" || "${{ needs.tests.result }}" == "failure" ]]; then + echo "One or more checks failed" + exit 1 + fi + echo "All checks passed" From fbe3c2d9b312ae60117b17d361a17974ca2f94f2 Mon Sep 17 00:00:00 2001 From: naaiyy Date: Tue, 17 Feb 2026 02:51:13 +0100 Subject: [PATCH 2/4] Fix formatting and clippy errors Run cargo fmt and remove empty lines after attributes/doc comments in sum_tree crate. Co-Authored-By: Claude Opus 4.6 --- crates/gpui/examples/native_button.rs | 20 +++--- crates/gpui/examples/native_text_field.rs | 53 ++++++++-------- crates/gpui/examples/native_toggle_group.rs | 70 +++++++++------------ crates/gpui/src/platform.rs | 4 +- crates/sum_tree/src/cursor.rs | 4 -- crates/sum_tree/src/sum_tree.rs | 3 - 6 files changed, 67 insertions(+), 87 deletions(-) diff --git a/crates/gpui/examples/native_button.rs b/crates/gpui/examples/native_button.rs index 069f343..dc29400 100644 --- a/crates/gpui/examples/native_button.rs +++ b/crates/gpui/examples/native_button.rs @@ -31,19 +31,19 @@ impl Render for NativeButtonExample { .text_color(fg) .child(format!("Count: {}", self.count)) .child( - native_button("increment", "Increment") - .on_click(cx.listener(|this, _event, _window, cx| { + native_button("increment", "Increment").on_click(cx.listener( + |this, _event, _window, cx| { this.count += 1; cx.notify(); - })), - ) - .child( - native_button("reset", "Reset") - .on_click(cx.listener(|this, _event, _window, cx| { - this.count = 0; - cx.notify(); - })), + }, + )), ) + .child(native_button("reset", "Reset").on_click(cx.listener( + |this, _event, _window, cx| { + this.count = 0; + cx.notify(); + }, + ))) } } diff --git a/crates/gpui/examples/native_text_field.rs b/crates/gpui/examples/native_text_field.rs index 39ff6d1..72e52bc 100644 --- a/crates/gpui/examples/native_text_field.rs +++ b/crates/gpui/examples/native_text_field.rs @@ -30,11 +30,7 @@ impl Render for TextFieldExample { .gap_4() .bg(bg) .text_color(fg) - .child( - div() - .text_xl() - .child("Native Text Field Demo"), - ) + .child(div().text_xl().child("Native Text Field Demo")) // Basic text field .child( div() @@ -45,10 +41,12 @@ impl Render for TextFieldExample { .child( native_text_field("basic") .placeholder("Type something...") - .on_change(cx.listener(|this, event: &gpui::TextChangeEvent, _window, cx| { - this.basic_text = event.text.clone(); - cx.notify(); - })), + .on_change(cx.listener( + |this, event: &gpui::TextChangeEvent, _window, cx| { + this.basic_text = event.text.clone(); + cx.notify(); + }, + )), ) .child( div() @@ -68,10 +66,12 @@ impl Render for TextFieldExample { native_text_field("password") .placeholder("Enter password...") .secure(true) - .on_change(cx.listener(|this, event: &gpui::TextChangeEvent, _window, cx| { - this.password_text = event.text.clone(); - cx.notify(); - })), + .on_change(cx.listener( + |this, event: &gpui::TextChangeEvent, _window, cx| { + this.password_text = event.text.clone(); + cx.notify(); + }, + )), ) .child( div() @@ -91,10 +91,12 @@ impl Render for TextFieldExample { native_text_field("search") .placeholder("Search (press Enter)...") .field_style(NativeTextFieldStyle::Rounded) - .on_submit(cx.listener(|this, event: &gpui::TextSubmitEvent, _window, cx| { - this.submitted_text = event.text.clone(); - cx.notify(); - })), + .on_submit(cx.listener( + |this, event: &gpui::TextSubmitEvent, _window, cx| { + this.submitted_text = event.text.clone(); + cx.notify(); + }, + )), ) .child( div() @@ -110,15 +112,14 @@ impl Render for TextFieldExample { .disabled(true), ) // Clear button - .child( - native_button("clear", "Clear All") - .on_click(cx.listener(|this, _event, _window, cx| { - this.basic_text.clear(); - this.password_text.clear(); - this.submitted_text.clear(); - cx.notify(); - })), - ) + .child(native_button("clear", "Clear All").on_click(cx.listener( + |this, _event, _window, cx| { + this.basic_text.clear(); + this.password_text.clear(); + this.submitted_text.clear(); + cx.notify(); + }, + ))) } } diff --git a/crates/gpui/examples/native_toggle_group.rs b/crates/gpui/examples/native_toggle_group.rs index a25e689..784adde 100644 --- a/crates/gpui/examples/native_toggle_group.rs +++ b/crates/gpui/examples/native_toggle_group.rs @@ -48,57 +48,43 @@ impl Render for ToggleGroupExample { .text_color(fg) .child(format!( "View: {} | Sort: {}", - Self::VIEW_MODES[self.view_mode], Self::SORT_ORDERS[self.sort_order] + Self::VIEW_MODES[self.view_mode], + Self::SORT_ORDERS[self.sort_order] )) // View mode selector .child( - div() - .flex() - .gap_3() - .items_center() - .child("View:") - .child( - native_toggle_group("view_mode", &Self::VIEW_MODES) - .selected_index(self.view_mode) - .segment_style(segmented_style) - .on_select(cx.listener(|this, event: &SegmentSelectEvent, _, cx| { - this.view_mode = event.index; - cx.notify(); - })), - ), + div().flex().gap_3().items_center().child("View:").child( + native_toggle_group("view_mode", &Self::VIEW_MODES) + .selected_index(self.view_mode) + .segment_style(segmented_style) + .on_select(cx.listener(|this, event: &SegmentSelectEvent, _, cx| { + this.view_mode = event.index; + cx.notify(); + })), + ), ) // Sort order selector .child( - div() - .flex() - .gap_3() - .items_center() - .child("Sort:") - .child( - native_toggle_group("sort_order", &Self::SORT_ORDERS) - .selected_index(self.sort_order) - .segment_style(segmented_style) - .on_select(cx.listener(|this, event: &SegmentSelectEvent, _, cx| { - this.sort_order = event.index; - cx.notify(); - })), - ), + div().flex().gap_3().items_center().child("Sort:").child( + native_toggle_group("sort_order", &Self::SORT_ORDERS) + .selected_index(self.sort_order) + .segment_style(segmented_style) + .on_select(cx.listener(|this, event: &SegmentSelectEvent, _, cx| { + this.sort_order = event.index; + cx.notify(); + })), + ), ) // Style selector (segmented control to change the style of the other controls) .child( - div() - .flex() - .gap_3() - .items_center() - .child("Style:") - .child( - native_toggle_group("style_selector", &Self::STYLE_NAMES) - .selected_index(self.style_index) - .on_select(cx.listener(|this, event: &SegmentSelectEvent, _, cx| { - this.style_index = event.index; - cx.notify(); - })), - ), + div().flex().gap_3().items_center().child("Style:").child( + native_toggle_group("style_selector", &Self::STYLE_NAMES) + .selected_index(self.style_index) + .on_select(cx.listener(|this, event: &SegmentSelectEvent, _, cx| { + this.style_index = event.index; + cx.notify(); + })), + ), ) } } diff --git a/crates/gpui/src/platform.rs b/crates/gpui/src/platform.rs index 8222ca6..39f5769 100644 --- a/crates/gpui/src/platform.rs +++ b/crates/gpui/src/platform.rs @@ -72,9 +72,9 @@ pub use keystroke::*; #[cfg(any(target_os = "linux", target_os = "freebsd"))] pub(crate) use linux::*; #[cfg(target_os = "macos")] -pub(crate) use mac::*; -#[cfg(target_os = "macos")] pub(crate) use mac::native_controls; +#[cfg(target_os = "macos")] +pub(crate) use mac::*; #[cfg(any(test, feature = "test-support"))] pub(crate) use test::*; #[cfg(target_os = "windows")] diff --git a/crates/sum_tree/src/cursor.rs b/crates/sum_tree/src/cursor.rs index caa1170..bc16d27 100644 --- a/crates/sum_tree/src/cursor.rs +++ b/crates/sum_tree/src/cursor.rs @@ -211,7 +211,6 @@ where } #[track_caller] - pub fn prev(&mut self) { self.search_backward(|_| true) } @@ -395,7 +394,6 @@ where { /// Returns whether we found the item you were seeking for. #[track_caller] - pub fn seek(&mut self, pos: &Target, bias: Bias) -> bool where Target: SeekTarget<'a, T::Summary, D>, @@ -410,7 +408,6 @@ where /// /// If we did not seek before, use seek instead in that case. #[track_caller] - pub fn seek_forward(&mut self, pos: &Target, bias: Bias) -> bool where Target: SeekTarget<'a, T::Summary, D>, @@ -452,7 +449,6 @@ where /// Returns whether we found the item you were seeking for. #[track_caller] - fn seek_internal( &mut self, target: &dyn SeekTarget<'a, T::Summary, D>, diff --git a/crates/sum_tree/src/sum_tree.rs b/crates/sum_tree/src/sum_tree.rs index cd7e7b6..aac522c 100644 --- a/crates/sum_tree/src/sum_tree.rs +++ b/crates/sum_tree/src/sum_tree.rs @@ -381,7 +381,6 @@ impl SumTree { /// A more efficient version of `Cursor::new()` + `Cursor::seek()` + `Cursor::item()`. /// /// Only returns the item that exactly has the target match. - pub fn find_exact<'a, 'slf, D, Target>( &'slf self, cx: ::Context<'a>, @@ -407,7 +406,6 @@ impl SumTree { } /// A more efficient version of `Cursor::new()` + `Cursor::seek()` + `Cursor::item()` - pub fn find<'a, 'slf, D, Target>( &'slf self, cx: ::Context<'a>, @@ -492,7 +490,6 @@ impl SumTree { } /// A more efficient version of `Cursor::new()` + `Cursor::seek()` + `Cursor::item()` - pub fn find_with_prev<'a, 'slf, D, Target>( &'slf self, cx: ::Context<'a>, From 3ddd9d4662e827ecfe6d452f810e1e3fd23fb85b Mon Sep 17 00:00:00 2001 From: naaiyy Date: Tue, 17 Feb 2026 02:58:07 +0100 Subject: [PATCH 3/4] Fix clippy warnings - Fix unnecessary_unwrap in key_dispatch.rs - Allow dead_code on native_controls module (in-progress work) - Allow unnecessary_unwrap in list.rs (borrow checker limitation) Co-Authored-By: Claude Opus 4.6 --- crates/gpui/src/elements/list.rs | 1 + crates/gpui/src/key_dispatch.rs | 4 ++-- crates/gpui/src/platform/mac.rs | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/crates/gpui/src/elements/list.rs b/crates/gpui/src/elements/list.rs index 49fb603..9a35b7e 100644 --- a/crates/gpui/src/elements/list.rs +++ b/crates/gpui/src/elements/list.rs @@ -572,6 +572,7 @@ impl StateInner { if self.scroll_handler.is_some() { let visible_range = self.visible_range(height, scroll_top); + #[allow(clippy::unnecessary_unwrap)] self.scroll_handler.as_mut().unwrap()( &ListScrollEvent { visible_range, diff --git a/crates/gpui/src/key_dispatch.rs b/crates/gpui/src/key_dispatch.rs index 1b92b9f..03c7eaa 100644 --- a/crates/gpui/src/key_dispatch.rs +++ b/crates/gpui/src/key_dispatch.rs @@ -199,8 +199,8 @@ impl DispatchTree { if let Some(context) = node.context.clone() { self.context_stack.push(context); } - if node.view_id.is_some() { - self.view_stack.push(node.view_id.unwrap()); + if let Some(view_id) = node.view_id { + self.view_stack.push(view_id); } self.node_stack.push(node_id); current_node_id = node.parent; diff --git a/crates/gpui/src/platform/mac.rs b/crates/gpui/src/platform/mac.rs index 5f0757d..6cd44e3 100644 --- a/crates/gpui/src/platform/mac.rs +++ b/crates/gpui/src/platform/mac.rs @@ -22,6 +22,7 @@ mod open_type; #[cfg(feature = "font-kit")] mod text_system; +#[allow(dead_code)] pub(crate) mod native_controls; mod platform; mod window; From 19a1b300682434dd0aeb31d98107a51347aab0bc Mon Sep 17 00:00:00 2001 From: naaiyy Date: Tue, 17 Feb 2026 03:03:37 +0100 Subject: [PATCH 4/4] Allow dead_code on NativeToggleGroupState In-progress native control element, fields will be used soon. Co-Authored-By: Claude Opus 4.6 --- crates/gpui/src/elements/native_toggle_group.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/gpui/src/elements/native_toggle_group.rs b/crates/gpui/src/elements/native_toggle_group.rs index c55ed0b..834c0ad 100644 --- a/crates/gpui/src/elements/native_toggle_group.rs +++ b/crates/gpui/src/elements/native_toggle_group.rs @@ -119,6 +119,7 @@ impl NativeToggleGroup { // Persisted element state // ============================================================================= +#[allow(dead_code)] struct NativeToggleGroupState { control_ptr: *mut c_void, target_ptr: *mut c_void,