diff --git a/apps/ios/Snowbound/Arranging.swift b/apps/ios/Snowbound/Arranging.swift index fa9fef9c03df21713e2424a0882dd7935bdcb547..f43914b9ecdae7aac1e35483f1d90ed2a76cc718 100644 --- a/apps/ios/Snowbound/Arranging.swift +++ b/apps/ios/Snowbound/Arranging.swift @@ -342,7 +342,7 @@ extension PagesViewController: UITableViewDragDelegate, UITableViewDropDelegate if indentable(rows, at) { add("Make Subpage") { [weak self] in self?.indent(id, by: 1) } } if rows[at].level > 1 { add("Promote Subpage") { [weak self] in self?.indent(id, by: -1) } } if !moveActions(item).isEmpty { - add("Move to Section…") { [weak self] in + add("Move to Section") { [weak self] in guard let self, let row = items.firstIndex(where: { $0.id == id }), let cell = tableView.cellForRow(at: IndexPath(row: row, section: 0)) else { return } @@ -571,7 +571,7 @@ extension NotebooksViewController: UICollectionViewDragDelegate, UICollectionVie if at < order.count - 1 { add("Move Down") { [weak self] in self?.shift(path, of: notebook, by: 1) } } } if !notebook.destinations(of: path).isEmpty { - add("Move…") { [weak self, weak cell] in + add("Move") { [weak self, weak cell] in guard let self, let cell else { return } sheet("Move", moveActions(path, of: notebook), from: cell, in: self) } diff --git a/apps/ios/Snowbound/Lists.swift b/apps/ios/Snowbound/Lists.swift index bc6039260532660a1dc4a3e2fc4e450b381130c0..b8e471e34cf843e6ace355b5863ce24da99a2bc6 100644 --- a/apps/ios/Snowbound/Lists.swift +++ b/apps/ios/Snowbound/Lists.swift @@ -94,10 +94,10 @@ final class NotebooksViewController: UICollectionViewController, UIDocumentPicke }) var actions: [UIMenuElement] = [ UIMenu(title: "New Notebook", options: .displayInline, children: places), - UIAction(title: "Open from Server…", image: UIImage(systemName: "server.rack")) { [weak self] _ in + UIAction(title: "Open from Server", image: UIImage(systemName: "server.rack")) { [weak self] _ in self?.connect() }, - UIAction(title: "Open Folder…", image: UIImage(systemName: "folder")) { [weak self] _ in + UIAction(title: "Open Folder", image: UIImage(systemName: "folder")) { [weak self] _ in self?.openFolder() }, ] @@ -114,7 +114,7 @@ final class NotebooksViewController: UICollectionViewController, UIDocumentPicke let more = UIMenu(children: [ UIDeferredMenuElement.uncached { [weak self] provide in var actions: [UIMenuElement] = [ - UIAction(title: "Sync Status…", image: UIImage(systemName: "arrow.triangle.2.circlepath")) { + UIAction(title: "Sync Status", image: UIImage(systemName: "arrow.triangle.2.circlepath")) { [weak self] _ in self.map(SyncViewController.present) } ] @@ -125,7 +125,7 @@ final class NotebooksViewController: UICollectionViewController, UIDocumentPicke }) } actions.append( - UIAction(title: "Personalize…", image: UIImage(systemName: "person.crop.circle")) { [weak self] _ in + UIAction(title: "Personalize", image: UIImage(systemName: "person.crop.circle")) { [weak self] _ in guard let self else { return } Author.ask(from: self) {} }) @@ -385,7 +385,7 @@ final class NotebooksViewController: UICollectionViewController, UIDocumentPicke return [UIMenu(options: .displayInline, children: [details, now])] } ?? [] let actions = [ - UIAction(title: "New Section…", image: UIImage(systemName: "plus.rectangle.portrait")) { + UIAction(title: "New Section", image: UIImage(systemName: "plus.rectangle.portrait")) { [weak self] _ in self?.newSection(in: notebook) }, UIAction(title: "Tags Summary", image: UIImage(systemName: "tag")) { [weak self] _ in @@ -403,13 +403,13 @@ final class NotebooksViewController: UICollectionViewController, UIDocumentPicke return UIMenu(children: status + actions + [close]) } let file = [ - UIAction(title: "Rename…", image: UIImage(systemName: "pencil")) { [weak self] _ in + UIAction(title: "Rename", image: UIImage(systemName: "pencil")) { [weak self] _ in self?.rename(folder, of: notebook) }, UIAction(title: "Duplicate", image: UIImage(systemName: "plus.square.on.square")) { [weak self] _ in self?.duplicate(folder, of: notebook) }, - UIAction(title: "Share…", image: UIImage(systemName: "square.and.arrow.up")) { [weak self] _ in + UIAction(title: "Share", image: UIImage(systemName: "square.and.arrow.up")) { [weak self] _ in self?.share(folder, from: notebook) }, UIAction(title: "Show in Files", image: UIImage(systemName: "folder")) { _ in diff --git a/apps/ios/Snowbound/PageViewController.swift b/apps/ios/Snowbound/PageViewController.swift index b7a7e6ab1f65218c26b5a428891f4a54c5b0520e..9b74022d5c8e89423d3e36b4498821ca6208c0e7 100644 --- a/apps/ios/Snowbound/PageViewController.swift +++ b/apps/ios/Snowbound/PageViewController.swift @@ -202,7 +202,7 @@ final class PageViewController: UIViewController, PHPickerViewControllerDelegate ]) return (Prototype.reading ? [readingAction()] : []) + [ insert, - UIAction(title: "Page Background…", image: UIImage(systemName: "paintpalette"), attributes: editable) { + UIAction(title: "Page Background", image: UIImage(systemName: "paintpalette"), attributes: editable) { [weak self] _ in self?.showPaper() }, themeMenu(), @@ -211,10 +211,10 @@ final class PageViewController: UIViewController, PHPickerViewControllerDelegate scene?.showTags(of: section.notebook, from: self) }, UIMenu(options: .displayInline, children: [ - UIAction(title: "Print…", image: UIImage(systemName: "printer")) { [weak self] _ in + UIAction(title: "Print", image: UIImage(systemName: "printer")) { [weak self] _ in self?.printPage(export: false) }, - UIAction(title: "Export as PDF…", image: UIImage(systemName: "doc.richtext")) { [weak self] _ in + UIAction(title: "Export as PDF", image: UIImage(systemName: "doc.richtext")) { [weak self] _ in self?.printPage(export: true) }, ]), diff --git a/apps/ios/Snowbound/Prototypes.swift b/apps/ios/Snowbound/Prototypes.swift index f957a7f21f12206a62c76ab08cc808210d0ab2c3..772608f0fd4e04de72b9a9a2eba7d94638696ac0 100644 --- a/apps/ios/Snowbound/Prototypes.swift +++ b/apps/ios/Snowbound/Prototypes.swift @@ -52,8 +52,8 @@ extension Prototype { open.title = "Open Existing Notebook" welcome.secondaryButton = open var elsewhere = [ - UIAction(title: "Open Folder…", image: UIImage(systemName: "folder")) { _ in openFolder() }, - UIAction(title: "Connect to Server…", image: UIImage(systemName: "server.rack")) { _ in connect() }, + UIAction(title: "Open Folder", image: UIImage(systemName: "folder")) { _ in openFolder() }, + UIAction(title: "Connect to Server", image: UIImage(systemName: "server.rack")) { _ in connect() }, ] if !ICloud.signedIn { elsewhere.append( diff --git a/arc/platforms.md b/arc/platforms.md index c85198ec19f76fce307aeddfdf116f84c7e65945..9fe226fe81f52583edeb5e8f8672a8ff0b85a6af 100644 --- a/arc/platforms.md +++ b/arc/platforms.md @@ -52,7 +52,7 @@ keyboard, the toolbar and the macOS menu bar all run commands from it. frame with the window's new size instead of stretching the last one. - A notebook on a mounted SMB share is opened through the embedded SMB client, signed in with the password the keychain keeps for that mount (see - [sync](sync.md) for why the mount itself isn't enough). Open Notebook from Server… reaches one + [sync](sync.md) for why the mount itself isn't enough). Open Notebook from Server reaches one by address instead, and keeps a password it asks to remember as the Finder does, an SMB internet password. - The menu bar (`menubar.rs`) is laid out as OneNote for Mac's. Its items are @@ -147,7 +147,7 @@ keyboard, the toolbar and the macOS menu bar all run commands from it. other writers) and takes OneNote's coordination bytes with byte-range locks, so both apps can have a section open on one machine. ReadDirectoryChangesW reports changes below a notebook, including other - clients' on a share. Open Notebook from Server… still uses the embedded + clients' on a share. Open Notebook from Server still uses the embedded client, its passwords in the Credential Manager. - The common file dialogs, task dialogs, the date and time picker, and the Spell Checking API (from Windows 8) are the system's; audio plays and diff --git a/arc/sync.md b/arc/sync.md index f232dd17ce6577a91851880acc8648a1044e04f0..40eb9668e51ffd7a90cf81382d428a6fd2b8a8d8 100644 --- a/arc/sync.md +++ b/arc/sync.md @@ -192,7 +192,7 @@ client with the account the system keeps for that mount. It falls back to the mount only when it can't sign in that way. A notebook can also be opened from its server's address, with no mount at all (File ▸ -Open Notebook from Server…), which is how Mac OS X 10.6 reaches a server that no longer +Open Notebook from Server), which is how Mac OS X 10.6 reaches a server that no longer speaks SMB1, the only version its Finder has. The notebook is kept by that address (`smb://[domain;]user@server/share/folder`), never with a password; the password lives in the keychain (the Secret Service on Linux) when the user asks to remember it, and diff --git a/corpus/page-versions/README.md b/corpus/page-versions/README.md index 9d1a9c5a0e4df0b77ab43560fa2b7b44cb70b2e4..f322aa1eb4e92d2debd2626324292efc7a1922a2 100644 --- a/corpus/page-versions/README.md +++ b/corpus/page-versions/README.md @@ -47,7 +47,7 @@ Versions is chosen. An open version is read-only under a yellow bar (RGB 255, 23 "This is an earlier version of the page. It will be deleted over time. Click here to restore or delete this version." What the version changed since the one before it is banded green (RGB 214, 255, 214). The bar's menu (`shots/02-version-menu.png`): Restore Version, Delete -Version, Copy Page To…; Delete All Versions in Section, Section Group, Notebook; Disable +Version, Copy Page To; Delete All Versions in Section, Section Group, Notebook; Disable History for This Notebook; Hide Page Versions. Share also has Hide Authors, Recent Edits and Find by Author (`shots/14`–`16`). diff --git a/corpus/section-color/README.md b/corpus/section-color/README.md index 3b40b39d998ba1d55610f8eb8cf2e1ebf52de9b1..769e7cf3fbe908258016571594134b1468b0a208 100644 --- a/corpus/section-color/README.md +++ b/corpus/section-color/README.md @@ -6,7 +6,7 @@ ends with Section Color, sixteen named colours and None (`section-color-menu.png appends a revision to the section's own file setting its metadata's `0x14001cbe` (COLORREF; `teal.one`), and None sets `0xFFFFFFFF` (`none.one`); the table of contents is left byte for byte. Notebook Properties (`notebook-properties.png`, from the notebook's -Rename… or Properties…) offers the same sixteen without None (`notebook-colors.png`) and +Rename or Properties) offers the same sixteen without None (`notebook-colors.png`) and appends a revision to the root `Open Notebook.onetoc2` setting its root's `0x14001cbe` (`before.onetoc2`, `after.onetoc2`). Its Display name is written to neither file: OneNote keeps it in its local `OneNoteOfflineCache.onecache`, so the hierarchy's `nickname` diff --git a/crates/snowbound/linux/README.md b/crates/snowbound/linux/README.md index 3563ef1e9f10afce4139fe04013cd4d39d4998da..c082be5d9cdd6bf0ac2ab98a5fb4854a2137c72d 100644 --- a/crates/snowbound/linux/README.md +++ b/crates/snowbound/linux/README.md @@ -11,7 +11,7 @@ cd snowbound-linux-x86_64 ./bin/snowbound ``` -Choose **Open Notebook…** in the notebook list and pick the notebook folder, +Choose **Open Notebook** in the notebook list and pick the notebook folder, the one holding the `.one` section files and `Open Notebook.onetoc2`. Snowbound remembers the notebooks you open. `--notebook FOLDER` opens one straight away. diff --git a/crates/snowbound/src/background.rs b/crates/snowbound/src/background.rs index 831b170ada5cf40f0e7552bf5038fd908a5871fd..5c117d2aea14d2a748d6bfb6c23282d707496472 100644 --- a/crates/snowbound/src/background.rs +++ b/crates/snowbound/src/background.rs @@ -161,7 +161,7 @@ pub fn menu( } match cells[index] { Cell::Color(None) | Cell::Art(None) | Cell::Rules(None) => label(ui, "None"), - Cell::ShowAll => label(ui, "Show All…"), + Cell::ShowAll => label(ui, "Show All"), Cell::Color(Some(color)) => { ui.leaf( "swatch", diff --git a/crates/snowbound/src/commands.rs b/crates/snowbound/src/commands.rs index 11ceec71783f2a0b116ff5a8afcf7c0e059790d9..4efcb12cf2acbc6b160c06930414ff5ccbed9011 100644 --- a/crates/snowbound/src/commands.rs +++ b/crates/snowbound/src/commands.rs @@ -260,12 +260,12 @@ const NONE: &[Chord] = &[]; /// OneNote 2010's chords off macOS; there, AppKit's and OneNote for Mac's. pub const COMMANDS: &[Command] = &[ - row!(Id::Settings, "Settings…", &[cmd(',')], &[cmd(',')]), - row!(Id::NewNotebook, "New Notebook…", NONE, NONE), - row!(Id::OpenNotebook, "Open Notebook…", &[cmd('o')], &[cmd('o')]), - row!(Id::OpenFromServer, "Open Notebook from Server…", NONE, NONE), - row!(Id::OpenShared, "Open Shared Notebook…", NONE, NONE), - row!(Id::LiveShare, "Live Share…", NONE, NONE), + row!(Id::Settings, "Settings", &[cmd(',')], &[cmd(',')]), + row!(Id::NewNotebook, "New Notebook", NONE, NONE), + row!(Id::OpenNotebook, "Open Notebook", &[cmd('o')], &[cmd('o')]), + row!(Id::OpenFromServer, "Open Notebook from Server", NONE, NONE), + row!(Id::OpenShared, "Open Shared Notebook", NONE, NONE), + row!(Id::LiveShare, "Live Share", NONE, NONE), row!(Id::CloseNotebook, "Close This Notebook", NONE, NONE), row!(Id::NewSection, "New Section", &[cmd('t')], &[cmd('t')]), row!(Id::NewSectionGroup, "New Section Group", NONE, NONE), @@ -280,7 +280,7 @@ pub const COMMANDS: &[Command] = &[ row!(Id::CopyPageLink, "Copy Link to Page", NONE, NONE), row!( Id::PasswordProtect, - "Password Protect This Section…", + "Password Protect This Section", NONE, NONE ), @@ -302,7 +302,7 @@ pub const COMMANDS: &[Command] = &[ ), row!( Id::SaveAs, - "Save As…", + "Save As", &[cmd('s').shift()], &[cmd('s').shift()] ), @@ -318,11 +318,11 @@ pub const COMMANDS: &[Command] = &[ NONE ), row!(Id::NextUnread, "Next Unread", NONE, NONE), - row!(Id::ExportPdf, "Export as PDF…", NONE, NONE), + row!(Id::ExportPdf, "Export as PDF", NONE, NONE), // Go to takes OneNote's Ctrl+P, and Pause its Ctrl+Alt+P. row!( Id::Print, - "Print…", + "Print", &[cmd('p').option().shift()], &[cmd('p').option().shift()] ), @@ -351,10 +351,10 @@ pub const COMMANDS: &[Command] = &[ &[cmd('f').option()], &[key('o').option()], ), - row!(Id::GoTo, "Go to Page or Section…", &[cmd('p')], &[cmd('p')]), + row!(Id::GoTo, "Go to Page or Section", &[cmd('p')], &[cmd('p')]), row!( Id::CommandPalette, - "Command Palette…", + "Command Palette", &[cmd('p').shift()], &[cmd('p').shift()] ), @@ -393,7 +393,7 @@ pub const COMMANDS: &[Command] = &[ row!(Id::MarkdownShortcuts, "Markdown Shortcuts", NONE, NONE), row!( Id::Spelling, - "Spelling…", + "Spelling", &[named(NamedKey::F7)], &[named(NamedKey::F7)] ), @@ -406,10 +406,10 @@ pub const COMMANDS: &[Command] = &[ ), row!(Id::PageColor, "Page Color", NONE, NONE), row!(Id::Table, "Table", NONE, NONE), - row!(Id::Picture, "Picture…", NONE, NONE), + row!(Id::Picture, "Picture", NONE, NONE), row!(Id::ScreenClipping, "Screen Clipping", NONE, NONE), - row!(Id::Attachment, "Attach File…", NONE, NONE), - row!(Id::Link, "Link…", &[cmd('k')], &[cmd('k')]), + row!(Id::Attachment, "Attach File", NONE, NONE), + row!(Id::Link, "Link", &[cmd('k')], &[cmd('k')]), row!(Id::InsertSpace, "Insert Space", NONE, NONE), row!( Id::Equation, @@ -465,7 +465,7 @@ pub const COMMANDS: &[Command] = &[ NONE, NONE ), - row!(Id::Transport(Transport::SeekTo), "Seek To…", NONE, NONE), + row!(Id::Transport(Transport::SeekTo), "Seek To", NONE, NONE), row!( Id::Transport(Transport::SeePlayback), "See Playback", @@ -596,8 +596,8 @@ pub const COMMANDS: &[Command] = &[ row!(Id::Style(8), "Quote", NONE, NONE), row!(Id::Style(9), "Code", NONE, NONE), row!(Id::Style(10), "Normal", NONE, NONE), - row!(Id::Themes, "Customize Theme…", NONE, NONE), - row!(Id::CustomizeTags, "Customize Tags…", NONE, NONE), + row!(Id::Themes, "Customize Theme", NONE, NONE), + row!(Id::CustomizeTags, "Customize Tags", NONE, NONE), row!( Id::RemoveTags, "Remove Tag", @@ -608,7 +608,7 @@ pub const COMMANDS: &[Command] = &[ row!(Id::ToDoList, "Make To-Do List", NONE, NONE), row!(Id::BulletedList, "Make Bulleted List", NONE, NONE), row!(Id::Help, "Snowbound Help", NONE, NONE), - row!(Id::CheckForUpdates, "Check for Updates…", NONE, NONE), + row!(Id::CheckForUpdates, "Check for Updates", NONE, NONE), ]; /// The most tags a list holds: MS-ONE's action types 0 to 99 number them. diff --git a/crates/snowbound/src/history.rs b/crates/snowbound/src/history.rs index 8e7ecdab19069b818739233798a54f83f18f8e10..e77e686e5da93c0de7e593adc8db5aab12f1b1c7 100644 --- a/crates/snowbound/src/history.rs +++ b/crates/snowbound/src/history.rs @@ -105,7 +105,7 @@ pub fn menu( drawn("Delete Version", art::DELETE), ui::popup::Item { disabled: sections.is_empty(), - ..drawn("Copy Page To…", art::COPY) + ..drawn("Copy Page To", art::COPY) }, ui::popup::Item { separated: true, diff --git a/crates/snowbound/src/keys.rs b/crates/snowbound/src/keys.rs index cf32509b99ba37b1e60d48d6399785559685e19e..5fddd4287419b39be7eb138e01c247a26075d625 100644 --- a/crates/snowbound/src/keys.rs +++ b/crates/snowbound/src/keys.rs @@ -78,7 +78,7 @@ fn label(chord: Chord) -> String { fn title(id: Command) -> String { match id { Command::Tag(place) => format!("Tag {}", place + 1), - id => crate::title(id).to_owned(), + id => commands::command(id).title.to_owned(), } } diff --git a/crates/snowbound/src/link.rs b/crates/snowbound/src/link.rs index b7ccea295901f515bdb4087a7afcb9a93089da8d..83d750dfcad8478afe467aafb5177459ee556d5a 100644 --- a/crates/snowbound/src/link.rs +++ b/crates/snowbound/src/link.rs @@ -303,7 +303,7 @@ impl State { item("Ignore"), Item { separated: true, - ..drawn("Spelling…", art::SPELLING) + ..drawn("Spelling", art::SPELLING) }, ], Some(correction) => { @@ -326,7 +326,7 @@ impl State { drawn("Add to Dictionary", art::ADD_TO_DICTIONARY), Item { separated: true, - ..drawn("Spelling…", art::SPELLING) + ..drawn("Spelling", art::SPELLING) }, ]); items @@ -344,7 +344,7 @@ impl State { .collect::>(); items.extend(if context.attachment.is_some() { // OneNote 2010's commands for the file itself; its clipboard holds text alone. - vec![drawn("Open", art::OPEN), drawn("Save As…", art::SAVE)] + vec![drawn("Open", art::OPEN), drawn("Save As", art::SAVE)] } else { let mut items = vec![ Item { @@ -362,7 +362,7 @@ impl State { Some(_) => items.extend([ Item { separated: true, - ..drawn("Edit Link…", art::LINK) + ..drawn("Edit Link", art::LINK) }, drawn("Copy Link to Paragraph", art::COPY_LINK), Item { @@ -375,7 +375,7 @@ impl State { None => items.extend([ Item { separated: true, - ..drawn("Link…", art::LINK) + ..drawn("Link", art::LINK) }, drawn("Copy Link to Paragraph", art::COPY_LINK), ]), @@ -414,7 +414,7 @@ impl State { self.view.correct(&correction, &chosen_text)? } "Delete Repeated Word" => self.view.correct(&correction, "")?, - "Spelling…" => { + "Spelling" => { self.open_spelling_pane(); return Ok(()); } @@ -441,7 +441,7 @@ impl State { } let response = match chosen_text.as_str() { "Open" => return self.open_attachment(&context.attachment.unwrap()), - "Save As…" => return self.save_attachment(&context.attachment.unwrap()), + "Save As" => return self.save_attachment(&context.attachment.unwrap()), "Cut" => self.view.copy(true)?, "Copy" => self.view.copy(false)?, "Paste" => { @@ -449,7 +449,7 @@ impl State { .push(Command::Page(canvas::interaction::Request::Paste)); return Ok(()); } - "Edit Link…" | "Link…" => { + "Edit Link" | "Link" => { self.open_link_dialog(); return Ok(()); } diff --git a/crates/snowbound/src/main.rs b/crates/snowbound/src/main.rs index 8639fbd391ea73a6506ef14af8660a3fce4256e5..5a26893f1f838b6e0a7146f187cec972013cece1 100644 --- a/crates/snowbound/src/main.rs +++ b/crates/snowbound/src/main.rs @@ -2413,7 +2413,7 @@ impl State { } else if ui::shell::split_button( ui, part, - title(id), + commands::command(id).title, icon, bar, None, @@ -2496,7 +2496,7 @@ impl State { } else if ui::shell::split_button( ui, part, - title(id), + commands::command(id).title, icon, None, status.checked, @@ -2798,7 +2798,7 @@ impl State { if ui::shell::split_button( ui, "pen", - title(Cmd::Pen), + commands::command(Cmd::Pen).title, art::PEN, bar, status.checked, @@ -4724,7 +4724,7 @@ fn conflict_bar(ui: &mut Ui, bar: Bar, sections: &[&str], steps: [bool; 2]) -> O ..Default::default() }, ui::popup::Item { - text: "Copy Page To…", + text: "Copy Page To", icon: Some(art::COPY), disabled: sections.is_empty(), ..Default::default() @@ -5349,7 +5349,9 @@ fn dropdown( Head::Split(id) if status_of(id).enabled => { let icon = artwork(id).unwrap_or_default(); let on = status_of(id).checked; - if ui::shell::split_button(ui, part, title(id), icon, None, on, menu).clicked { + if ui::shell::split_button(ui, part, commands::command(id).title, icon, None, on, menu) + .clicked + { choice = Some(Choice::Command(id)); } tip(ui, id); @@ -5368,7 +5370,7 @@ fn dropdown( Head::Split(id) => { let icon = artwork(id).unwrap_or_default(); let anchor = ui::shell::menu_button(ui, part, icon, None, menu); - name(ui, button, title(id)); + name(ui, button, commands::command(id).title); anchor } Head::Tag(_, tag) => { @@ -5422,7 +5424,7 @@ fn dropdown( let options: Vec<_> = entries .iter() .map(|entry| match *entry { - Entry::Open(_, id) if runs(id) => format!("{} Options", title(id)), + Entry::Open(_, id) if runs(id) => format!("{} Options", commands::command(id).title), _ => String::new(), }) .collect(); @@ -5723,12 +5725,12 @@ fn tag_tip(ui: &mut Ui, place: usize, tag: &canvas::editor::NoteTag) { /// A tooltip naming command `id` and its chord on the box built last. fn tip(ui: &mut Ui, id: commands::Id) { - ui::popup::tooltip(ui, title(id), &commands::shortcut(id), None); -} - -/// Command `id`'s title without the menu's ellipsis, naming the command, not a dialog it opens. -fn title(id: commands::Id) -> &'static str { - commands::command(id).title.trim_end_matches('…') + ui::popup::tooltip( + ui, + commands::command(id).title, + &commands::shortcut(id), + None, + ); } /// Whether each toolbar group stands on a face of its own. diff --git a/crates/snowbound/src/menubar.rs b/crates/snowbound/src/menubar.rs index e03f4cb562b66dee1d4af0faa4a3b7c672d4158d..66e9ec66c324e5b055ac40350d7429eb9a8d0581 100644 --- a/crates/snowbound/src/menubar.rs +++ b/crates/snowbound/src/menubar.rs @@ -102,7 +102,7 @@ const MENUS: &[Item] = &[ C(Id::Search), C(Id::SearchResults), S, - Item::System("Start Dictation…", "startDictation:", None), + Item::System("Start Dictation", "startDictation:", None), Item::System( "Emoji & Symbols", "orderFrontCharacterPalette:", diff --git a/crates/snowbound/src/menus.rs b/crates/snowbound/src/menus.rs index 198c6e33aa6bb2e705583bcec740bebd4bd318dd..04d0cc247e1110a9c8bbbc8b1a3abea2ef5913f5 100644 --- a/crates/snowbound/src/menus.rs +++ b/crates/snowbound/src/menus.rs @@ -342,7 +342,7 @@ impl State { item(Action::Copy, "Copy To", nowhere(), false), ], Target::Section { path, .. } if crate::recycle::binned(path) => vec![ - item(Action::SaveAs, "Save As…", false, false), + item(Action::SaveAs, "Save As", false, false), item(Action::Move, "Restore To", nowhere(), false), item(Action::EmptyRecycleBin, "Empty Recycle Bin", false, true), item(Action::Colors, "Section Color", false, true), @@ -360,7 +360,7 @@ impl State { item(Action::NewPage, "New Page", false, true), // OneNote offers this beside New Page, which is a plain + here. item(Action::NewSubpage, "New Subpage", false, false), - item(Action::Theme, "Theme…", false, true), + item(Action::Theme, "Theme", false, true), ]; // Levels and versions are known once the section is open. let Some(session) = self.session.as_ref().filter(|_| self.open(library, path)) @@ -400,7 +400,7 @@ impl State { let section = matches!(target, Target::Section { .. }); let mut actions = vec![item(Action::Rename, "Rename", false, false)]; if section { - actions.push(item(Action::SaveAs, "Save As…", false, false)); + actions.push(item(Action::SaveAs, "Save As", false, false)); } actions.extend([ item(Action::Delete, "Delete", false, false), @@ -412,7 +412,7 @@ impl State { actions.extend([ item( Action::Password, - "Password Protect This Section…", + "Password Protect This Section", library.catalog().is_none(), true, ), @@ -423,7 +423,7 @@ impl State { section_file(library, path).is_none(), false, ), - item(Action::Theme, "Theme…", false, false), + item(Action::Theme, "Theme", false, false), ]); } actions @@ -433,10 +433,10 @@ impl State { let last = self.notebooks.len().saturating_sub(1); let unread = self.unread_notebook(library); vec![ - item(Action::Rename, "Rename…", false, false), + item(Action::Rename, "Rename", false, false), item( Action::SaveAs, - "Save As…", + "Save As", library.catalog().is_none(), false, ), @@ -493,7 +493,7 @@ impl State { library.folder().is_none(), true, ), - item(Action::Theme, "Theme…", false, false), + item(Action::Theme, "Theme", false, false), item( Action::RecycleBin, "Notebook Recycle Bin", @@ -502,7 +502,7 @@ impl State { ), item( Action::Properties, - "Properties…", + "Properties", library.catalog().is_none(), false, ), diff --git a/crates/snowbound/src/options.rs b/crates/snowbound/src/options.rs index 21b721ec48b64cd25f429bf474a5de621a32dce0..533525d71b3d1bfdaa6fd16d43dad63a48ab3982 100644 --- a/crates/snowbound/src/options.rs +++ b/crates/snowbound/src/options.rs @@ -992,7 +992,7 @@ fn installed(state: &mut State, _: &mut Options) { let ui = &mut state.ui; if crate::desktop::uninstallable() { path(ui, &crate::desktop::binary().unwrap_or_default()); - if ui::button(ui, "uninstall", "Uninstall…").clicked { + if ui::button(ui, "uninstall", "Uninstall").clicked { crate::desktop::uninstall(&state.proxy); } } else if crate::desktop::installable() { diff --git a/crates/snowbound/src/print.rs b/crates/snowbound/src/print.rs index b9beba4d60f3c9465de59f2b39b8a4d4e52ad32e..c41daa8bac98c72967205ee167872382c8284621 100644 --- a/crates/snowbound/src/print.rs +++ b/crates/snowbound/src/print.rs @@ -257,11 +257,7 @@ impl State { }); crate::buttons(ui); let cancel = ui::button(ui, "cancel", "Cancel").clicked; - let action = if dialog.export { - "Export…" - } else { - "Print…" - }; + let action = if dialog.export { "Export" } else { "Print" }; let go = ui::button(ui, "go", action).clicked || entered; ui.close(); ui.close(); diff --git a/crates/snowbound/src/protection.rs b/crates/snowbound/src/protection.rs index 40ffa26631cb33a9c0c50088974158510639e4bd..d0ab31f8de8f18ccd66cd023c56ce6921cead79e 100644 --- a/crates/snowbound/src/protection.rs +++ b/crates/snowbound/src/protection.rs @@ -442,9 +442,9 @@ impl State { }; text(ui, "status", &status, false); buttons = if protected { - &["Change Password…", "Remove Password…", "Lock All", "Close"] + &["Change Password", "Remove Password", "Lock All", "Close"] } else { - &["Set Password…", "Lock All", "Close"] + &["Set Password", "Lock All", "Close"] }; } Dialog::Set([value, confirm], refused) => { @@ -527,9 +527,9 @@ impl State { self.ui.close_popup(id()); return self.lock_all(); } - (Some("Set Password…"), _) => Some(Dialog::Set(Default::default(), None)), - (Some("Change Password…"), _) => Some(Dialog::Change(Default::default(), None)), - (Some("Remove Password…"), _) => Some(Dialog::Remove(Zeroizing::default(), false)), + (Some("Set Password"), _) => Some(Dialog::Set(Default::default(), None)), + (Some("Change Password"), _) => Some(Dialog::Change(Default::default(), None)), + (Some("Remove Password"), _) => Some(Dialog::Remove(Zeroizing::default(), false)), (Some(_), Dialog::Unlock(value, _)) => match library.unlock(&path, &value) { Ok(()) => { self.commands diff --git a/crates/snowbound/src/recording.rs b/crates/snowbound/src/recording.rs index 6576327f92c2947c1f34d6312f19bc925a59dcbf..6e33fa37ecc1c1e78af7bb6afa0b7e7677a78422 100644 --- a/crates/snowbound/src/recording.rs +++ b/crates/snowbound/src/recording.rs @@ -495,7 +495,7 @@ impl State { let title = crate::commands::command(crate::commands::Id::Transport(Transport::SeekTo)) .title; - node.set_label(title.trim_end_matches('…')); + node.set_label(title); node.set_value(clock_text); } if clicked { diff --git a/crates/snowbound/src/save_as.rs b/crates/snowbound/src/save_as.rs index e98f4c11226b869c7c1cef62d554e0cabd1cbb87..6e6d683d2813acf85b89aa42d4040be3768a3199 100644 --- a/crates/snowbound/src/save_as.rs +++ b/crates/snowbound/src/save_as.rs @@ -135,7 +135,7 @@ impl State { } crate::buttons(ui); let cancel = ui::button(ui, "cancel", "Cancel").clicked; - let go = ui::button(ui, "go", "Save As…").clicked || entered; + let go = ui::button(ui, "go", "Save As").clicked || entered; ui.close(); ui.close(); if !go && !cancel { diff --git a/crates/snowbound/src/sidebar.rs b/crates/snowbound/src/sidebar.rs index 21bb2c4299646f946b182c018a09f3545741dfa2..bbc3814d3dd5dd5d4871746f3f154b2684b52e90 100644 --- a/crates/snowbound/src/sidebar.rs +++ b/crates/snowbound/src/sidebar.rs @@ -279,7 +279,7 @@ fn sidebar( ( "shared", Leading::Icon(art::LINK), - "Open Shared…", + "Open Shared", Action::OpenShared, ), ( @@ -1267,13 +1267,13 @@ impl crate::State { ( "shared", Leading::Icon(art::LINK), - "Open Shared Notebook…", + "Open Shared Notebook", crate::Command::OpenShared, ), ( "server", Leading::Icon(art::SERVER), - "Open Notebook from Server…", + "Open Notebook from Server", crate::Command::OpenFromServer(None), ), ] diff --git a/crates/snowbound/src/symbol.rs b/crates/snowbound/src/symbol.rs index 828825a4486c229d284c9bbaf80a333943ca419e..a6181a3779f81a0be331a0d7ec59e16f7ae94441 100644 --- a/crates/snowbound/src/symbol.rs +++ b/crates/snowbound/src/symbol.rs @@ -101,7 +101,7 @@ pub fn gallery(ui: &mut Ui, id: Id, anchor: Anchor, symbols: &[char]) -> Option< "more", Spec { size: [fill(), fill()], - text: Some("More Symbols…"), + text: Some("More Symbols"), icon: Some(art::SYMBOL), gap: 6.0, ..Spec::default() diff --git a/crates/snowbound/src/sync.rs b/crates/snowbound/src/sync.rs index 1afc76c366dc9064054792228e8bc3fac3c5a6a6..a9572e02fa1195b5fcbe634d966aaeb433ff7dcc 100644 --- a/crates/snowbound/src/sync.rs +++ b/crates/snowbound/src/sync.rs @@ -739,7 +739,7 @@ fn build(ui: &mut Ui, facts: &Facts) -> Picked { &format!("Using the system’s connection. Snowbound couldn’t sign in: {notice}"), theme.text_dim, ); - picked.sign_in = ui::button(ui, "sign-in", "Sign In…").clicked; + picked.sign_in = ui::button(ui, "sign-in", "Sign In").clicked; } ui.close(); } diff --git a/crates/snowbound/src/tags.rs b/crates/snowbound/src/tags.rs index 2eb7950e3f669491f2f6c9a3454e41f0b02e9301..73cdffddbe9c5ed81711f35a9718bd7fbd8c5dac 100644 --- a/crates/snowbound/src/tags.rs +++ b/crates/snowbound/src/tags.rs @@ -515,11 +515,11 @@ impl State { let new = button( ui, "new", - "New Tag…", + "New Tag", list.tags.len() < commands::TAGS && list.editor.is_none(), ); modify = modify.or_else(|| { - button(ui, "modify", "Modify Tag…", list.selected.is_some()) + button(ui, "modify", "Modify Tag", list.selected.is_some()) .then_some(list.selected) .flatten() }); @@ -1035,7 +1035,7 @@ fn gallery(ui: &mut Ui, id: Id, anchor: Anchor, snowbound: bool) -> Option ..Spec::default() }, ); - if ui::button(ui, "picture", "Custom Image…").clicked { + if ui::button(ui, "picture", "Custom Image").clicked { picked = Some(Pick::Picture); } } diff --git a/crates/snowbound/src/themes.rs b/crates/snowbound/src/themes.rs index 76e49440bc97b971925e496ce34d9431ba3e0aa5..8d4c9dec6c6eb7f8cda74dd976d32dfab5194691 100644 --- a/crates/snowbound/src/themes.rs +++ b/crates/snowbound/src/themes.rs @@ -807,7 +807,7 @@ pub(crate) fn gallery( "customize", Spec { size: [fill(), fill()], - text: Some("Customize…"), + text: Some("Customize"), ..Spec::default() }, ); diff --git a/crates/snowbound/src/unpack.rs b/crates/snowbound/src/unpack.rs index ea21c94e1fb1e9a6bf4746a374327c74b1f994db..2267d6d2048ceab9596a5ac7e52de25be80f0df2 100644 --- a/crates/snowbound/src/unpack.rs +++ b/crates/snowbound/src/unpack.rs @@ -154,7 +154,7 @@ impl State { ..Spec::default() }, ); - let browse = ui::button(ui, "browse", "Browse…").clicked; + let browse = ui::button(ui, "browse", "Browse").clicked; let root = dialog.folder.join(dialog.name.trim()); let full = format!("Full path: {}", root.display()); ui.leaf( diff --git a/crates/snowbound/tests/replay.rs b/crates/snowbound/tests/replay.rs index cad9fc302f62c992210107a05471808f27ad4203..e753863914c8465d54285a5a7743ecab6331173c 100644 --- a/crates/snowbound/tests/replay.rs +++ b/crates/snowbound/tests/replay.rs @@ -452,7 +452,7 @@ fn a_version_copied_into_its_section_is_listed_and_found() { let notebook = Path::new(env!("CARGO_MANIFEST_DIR")).join("../../corpus/page-versions/candidate-restore"); let mut steps = version_menu(); - // Copy Page To…, then the section itself. + // Copy Page To, then the section itself. steps.extend(["key Down", "key Down", "key Down", "key Enter", "settle"].map(String::from)); steps.extend(["key Down", "key Enter", "accessibility copied"].map(String::from)); steps.extend(search("Second author", "found")); @@ -674,7 +674,7 @@ fn open_shared_notebook_is_offered_with_notebooks_open() { let [sidebar, dialog] = replay_with(&scratch, Some(¬ebook), &steps, &variables) .try_into() .unwrap(); - assert!(sidebar.contains(r#""Open Shared…""#), "{sidebar}"); + assert!(sidebar.contains(r#""Open Shared""#), "{sidebar}"); assert!( dialog.contains(r#"Dialog "Open Shared Notebook""#), "{dialog}" diff --git a/tools/RELEASE.md b/tools/RELEASE.md index 9b022c19c1e54439111ffda0a9b61580276b8ecf..c47cd4ceeece238873d65f29da362e6f8475086a 100644 --- a/tools/RELEASE.md +++ b/tools/RELEASE.md @@ -230,7 +230,7 @@ frames from the symbol table. `update.rs` runs one thread. With automatic checks on (Options, General) and a published build, it checks shortly after launch and then daily, skipping while -Work Offline is on; Check for Updates… (the app menu on macOS, the command +Work Offline is on; Check for Updates (the app menu on macOS, the command palette elsewhere) checks at once and reports what it found. A check reads `latest.json`, then the named build's `build.json` and signature, then `history.json` and the `build.json` of each build since its own, and @@ -241,7 +241,7 @@ the app unpacked into `.Snowbound.app.update` next to the bundle on macOS, the executable into `.snowbound.update` next to it on Linux (`.snowbound.exe.update` on Windows). The sync status icon gets a dot, and its popup says what the update changes, unfolding to the titles, and offers Build Folder and Restart to -Update; Check for Updates… lists them in its dialog. +Update; Check for Updates lists them in its dialog. Restart to Update quits the app and starts the old executable with `--finish-update`, which waits for the app to exit, renames the old bundle (or diff --git a/tools/canvas/README.md b/tools/canvas/README.md index 67d0bb8a4acab61b925c1593a1de1d5c2f7a6a96..55fa4e6e2fa6f534297661bb15d4469a73c9a8c3 100644 --- a/tools/canvas/README.md +++ b/tools/canvas/README.md @@ -50,7 +50,7 @@ snowbound title bar · toolbar · section frame · page tabs · the page as a `--notebook FOLDER` opens a notebook laid out as OneNote lays one out. The title bar shows the application's icon and the notebook's name; below it two rows of toolbar buttons follow the Home ribbon's Basic Text group, the first nine tags and zoom (only zoom acts yet). Readable top-level sections are tabs in the notebook's order, each leaning over the next at 45° with a faint highlight along its top, and the open one on top, casting a soft shadow and framing the page and the page tabs on the right in its colour, which shades slightly down the window; a tab that opens rises to meet the frame as its outline fades in. The frame's top corners and the page's corners are rounded concentric with the window's. The open page's tab is the page's colour and joins it with rounded inside corners; subpages are indented. The interface follows the system's light or dark appearance, and in the dark one the page's paper darkens and text left at OneNote's automatic colour turns light (except on a highlight), resolved when painting so nothing re-lays out; explicit colours, highlights, pictures and ink keep theirs, except that the background art of OneNote 2010's page templates, recognised by the picture's hash, paints from bundled vector recreations drawn for the paper. Sections take their stored colour's hue at a saturation and lightness chosen for each appearance. The section's colour is also the interface accent, easing to the next section's when another opens. The search box, New Page and the page-tab toggle sit above the page tabs. Command-F searches the page titles; Enter opens the first match and Escape clears it. A page that also changed on another computer shows Keep mine / Keep theirs above it. `--section FILE TITLE` opens one section the same way at that page. Section files must be regular files; discovery rejects symbolic links. -Launched without a file, the app reopens the notebooks open when it last closed, at the one shown last, or shows "No notebooks open" with New Notebook and Open Existing. Settings (the open notebooks, the sidebar, recent fonts and the user name edits are stored under, which Settings… (⌘,, Ctrl+, on Linux, or Options in the sidebar) changes and which starts as the account's full name) are JSON in `~/Library/Application Support/Snowbound/settings.json` or `$XDG_CONFIG_HOME/snowbound`; `--settings FILE` uses another file, `--notebook FOLDER` adds a notebook to them, and `--screenshot` never writes them. Open Existing takes a notebook folder, its `Open Notebook.onetoc2` or a section file, which opens in the notebook its folders make up. A notebook on a mounted SMB share opens through the embedded SMB client, signed in with the password the system keychain holds, and through the mount only when that fails. The notebook button left of the section tabs opens OneNote 2010's navigation bar: the open notebooks with their sections and section groups, the open section marked; dragging a row reorders a folder or, onto a group, moves into it, and right-clicking a row, a section tab or a page tab offers OneNote's commands (Rename, Delete to the notebook's recycle bin, New Section, New Section Group, Close This Notebook; Delete, New Page, Make Subpage, Promote Subpage). Page tabs drag to reorder. The `+` above the page tabs adds a page at the end of the section, titled with its date and time as OneNote titles one, and puts the caret in its title; until its body is typed in, drawn on or clicked, templates offer our recreations of OneNote 2010's art (Ivy first), its page colours and Informal Meeting Notes' content, written as ops (`corpus/notebook-management`). +Launched without a file, the app reopens the notebooks open when it last closed, at the one shown last, or shows "No notebooks open" with New Notebook and Open Existing. Settings (the open notebooks, the sidebar, recent fonts and the user name edits are stored under, which Settings (⌘,, Ctrl+, on Linux, or Options in the sidebar) changes and which starts as the account's full name) are JSON in `~/Library/Application Support/Snowbound/settings.json` or `$XDG_CONFIG_HOME/snowbound`; `--settings FILE` uses another file, `--notebook FOLDER` adds a notebook to them, and `--screenshot` never writes them. Open Existing takes a notebook folder, its `Open Notebook.onetoc2` or a section file, which opens in the notebook its folders make up. A notebook on a mounted SMB share opens through the embedded SMB client, signed in with the password the system keychain holds, and through the mount only when that fails. The notebook button left of the section tabs opens OneNote 2010's navigation bar: the open notebooks with their sections and section groups, the open section marked; dragging a row reorders a folder or, onto a group, moves into it, and right-clicking a row, a section tab or a page tab offers OneNote's commands (Rename, Delete to the notebook's recycle bin, New Section, New Section Group, Close This Notebook; Delete, New Page, Make Subpage, Promote Subpage). Page tabs drag to reorder. The `+` above the page tabs adds a page at the end of the section, titled with its date and time as OneNote titles one, and puts the caret in its title; until its body is typed in, drawn on or clicked, templates offer our recreations of OneNote 2010's art (Ivy first), its page colours and Informal Meeting Notes' content, written as ops (`corpus/notebook-management`). As in OneNote 2010, Notebook Recycle Bin (File menu, a notebook's context menu, or the palette) shows the notebook's recycle bin as its own row of tabs, read-only under a bar: a page's context menu restores it to a section, keeping its identity, copies it out, or deletes it for good, a section's restores it to a folder, and Empty Recycle Bin deletes what it holds (`corpus/recycle-bin-view`). Pages another author changed since they were viewed are bold in the page list, and so are their section's tab and row and the groups and notebook holding them, until left or marked read (Mark as Read, Ctrl+Q off macOS; Mark Notebook as Read; Next Unread; Show Unread Changes in This Notebook); what was read is kept in the cache folder's `read.json`, as OneNote keeps it in its cache. Save As (⇧⌘S) writes the page or section as a OneNote section, the notebook as a OneNote package, or any of them as a PDF; opening a `.onepkg` asks, as Unpack Notebook does, for its name, colour and folder (`corpus/notebook-package`).