diff --git a/assets/locales/pending/issue-report-ctrl-enter.json b/assets/locales/pending/issue-report-ctrl-enter.json new file mode 100644 index 0000000000..1bea67a0b6 --- /dev/null +++ b/assets/locales/pending/issue-report-ctrl-enter.json @@ -0,0 +1,30 @@ +{ + "en": { + "Ctrl+Enter continues on GitHub.": "Ctrl+Enter continues on GitHub.", + "⌘Enter continues on GitHub.": "⌘Enter continues on GitHub." + }, + "ar": { + "Ctrl+Enter continues on GitHub.": "Ctrl+Enter يتابع في GitHub.", + "⌘Enter continues on GitHub.": "⌘Enter يتابع في GitHub." + }, + "de": { + "Ctrl+Enter continues on GitHub.": "Strg+Enter geht weiter zu GitHub.", + "⌘Enter continues on GitHub.": "⌘Enter geht weiter zu GitHub." + }, + "he": { + "Ctrl+Enter continues on GitHub.": "Ctrl+Enter ממשיך ב־GitHub.", + "⌘Enter continues on GitHub.": "⌘Enter ממשיך ב־GitHub." + }, + "ja": { + "Ctrl+Enter continues on GitHub.": "Ctrl+EnterでGitHubに進みます。", + "⌘Enter continues on GitHub.": "⌘EnterでGitHubに進みます。" + }, + "vi": { + "Ctrl+Enter continues on GitHub.": "Nhấn Ctrl+Enter để tiếp tục trên GitHub.", + "⌘Enter continues on GitHub.": "Nhấn ⌘Enter để tiếp tục trên GitHub." + }, + "zh": { + "Ctrl+Enter continues on GitHub.": "按Ctrl+Enter在GitHub中继续。", + "⌘Enter continues on GitHub.": "按⌘Enter在GitHub中继续。" + } +} diff --git a/crates/ui-egui/src/issue_report.rs b/crates/ui-egui/src/issue_report.rs index d6bd0cf01f..2e5b541f1f 100644 --- a/crates/ui-egui/src/issue_report.rs +++ b/crates/ui-egui/src/issue_report.rs @@ -1132,6 +1132,52 @@ mod tests { } } + /// Ctrl+Enter (⌘Enter on a Mac) continues on GitHub from a field, without a line break, and + /// asks for a description first like the button does (#7203). Holding it opens GitHub once. + #[test] + fn issue_report_ctrl_enter_continues_on_github() { + let mut h = crate::scenario::Harness::new(); + h.app.home.open = false; + h.app.issue_report.draft = Some(draft_for(&h.app, None, None)); + h.frames(8); + assert!(h.widget(form::shortcut_hint(h.ctx.os())).is_some(), "the dialog says so"); + // As the platforms send it: ⌘ sets mac_cmd and command, Ctrl elsewhere ctrl and command. + // egui marks a press of a key it already holds down as a repeat. + let key = |pressed: bool| { + let modifiers = if h.ctx.os() == egui::os::OperatingSystem::Mac { + egui::Modifiers { mac_cmd: true, command: true, ..Default::default() } + } else { + egui::Modifiers { ctrl: true, command: true, ..Default::default() } + }; + egui::Event::Key { key: egui::Key::Enter, physical_key: None, pressed, repeat: false, modifiers } + }; + let (down, up) = (key(true), key(false)); + // Held for `repeats` frames after the press, then released. + let press = |h: &mut crate::scenario::Harness, repeats: usize| { + let mut commands = Vec::new(); + for _ in 0..=repeats { + h.frame_with(vec![down.clone()]); + commands.extend(h.output.commands.clone()); + } + h.frame_with(vec![up.clone()]); + commands.extend(h.output.commands.clone()); + h.frames(2); + commands.extend(h.output.commands.clone()); + commands + }; + let commands = press(&mut h, 0); + assert!(!commands.iter().any(|c| matches!(c, egui::OutputCommand::OpenUrl(_)))); + assert!(h.app.issue_report.draft.as_ref().unwrap().missing_description, "an empty description is asked for"); + h.frame_with(vec![egui::Event::Text("The preview disappeared".into())]); + // Held down, it continues on GitHub once: its repeats open nothing more. + let commands = press(&mut h, 3); + let opened = commands.iter().filter(|c| matches!(c, egui::OutputCommand::OpenUrl(url) if url.url.starts_with(ISSUE_URL))).count(); + assert_eq!(opened, 1, "{commands:?}"); + let draft = h.app.issue_report.draft.as_ref().unwrap(); + assert_eq!(draft.description, "The preview disappeared", "no line break"); + assert!(draft.opened_github); + } + #[test] fn crash_draft_marks_later_detection_without_losing_native_evidence() { let message = @@ -1411,6 +1457,9 @@ mod tests { draft.image = Some(Arc::new(ColorImage::new([4, 3], vec![egui::Color32::GREEN; 12]))); h.app.issue_report.draft = Some(draft); h.frames(4); + // The screenshot's buttons sit low in the review's scroll area: scrolled into view first. + h.call("ui.scroll", json!({"x":800,"y":600,"delta":-1000})); + h.frames(2); for (path, saved) in [(h.dir.join("report.png"), true), (h.dir.join("missing").join("report.png"), false)] { let answer = path.to_string_lossy().to_string(); h.app.services.pick_save = Some(Box::new(move |_, _| Box::pin(std::future::ready(Some(answer.clone()))))); diff --git a/crates/ui-egui/src/issue_report/form.rs b/crates/ui-egui/src/issue_report/form.rs index 2aa7366762..021efa6abb 100644 --- a/crates/ui-egui/src/issue_report/form.rs +++ b/crates/ui-egui/src/issue_report/form.rs @@ -89,7 +89,21 @@ pub(super) fn show(app: &mut SolveApp, draft: &mut Draft, ctx: &egui::Context) - let t = crate::theme::Tokens::get(); let screen = ctx.content_rect(); let cards = ((screen.width() - 2.0 * t.space_16) / t.form_card_width).clamp(0.5, 2.6); - let (closed, action) = ui_kit::Window::new(Id::new("sc_issue_report"), "bug_report", tr_label("Report a bug")) + // Ctrl+Enter (⌘Enter on a Mac) in any field continues on GitHub. Read before the fields see + // it, so it adds no line break. Only the press counts: the repeats of a held key are dropped, + // so holding it opens GitHub once. + let submit = ctx.input_mut(|i| { + let mut pressed_now = false; + i.events.retain(|e| match e { + egui::Event::Key { key: egui::Key::Enter, pressed, repeat, modifiers, .. } if modifiers.command => { + pressed_now |= *pressed && !*repeat; + false + } + _ => true, + }); + pressed_now + }); + let (closed, mut action) = ui_kit::Window::new(Id::new("sc_issue_report"), "bug_report", tr_label("Report a bug")) .cards(cards) .anchor(egui::Align2::CENTER_TOP, vec2(0.0, t.space_16)) .fields() @@ -164,6 +178,7 @@ pub(super) fn show(app: &mut SolveApp, draft: &mut Draft, ctx: &egui::Context) - draft.missing_description = false; } } + ui_kit::text(ui, tr_label(shortcut_hint(ui.ctx().os())), ui_kit::Text::Note("shortcut")); let steps = answer( ui, "Steps to reproduce (optional)", @@ -194,6 +209,9 @@ pub(super) fn show(app: &mut SolveApp, draft: &mut Draft, ctx: &egui::Context) - }); }); }); + if submit && action == ui_kit::Action::None { + action = ui_kit::Action::Ok; + } // TextEdit applies this frame's events while it is drawn. Export only after every editor // has processed its input, including diagnostic redactions. match action { @@ -223,3 +241,8 @@ pub(super) fn show(app: &mut SolveApp, draft: &mut Draft, ctx: &egui::Context) - } (retake, closed || action == ui_kit::Action::Cancel) } + +/// The keys that continue on GitHub from any field (#7203), as this computer spells them. +pub(super) fn shortcut_hint(os: egui::os::OperatingSystem) -> &'static str { + if os == egui::os::OperatingSystem::Mac { "⌘Enter continues on GitHub." } else { "Ctrl+Enter continues on GitHub." } +}