From 4e1be731f0bc52c2cad937f941592a351e41d3a0 Mon Sep 17 00:00:00 2001 From: Tastaturtaste <31124715+Tastaturtaste@users.noreply.github.com> Date: Sat, 20 Jan 2024 15:04:06 +0100 Subject: [PATCH] Add shift + navigation functionality through reedline (#11535) This PR should close #1171 # Description This PR introduces the capability to select text using the existing move.. `EditCommand`s of `reedline`. Those commands are extended with an optional parameter specifying if text should be selected while navigating. This enables a workflow familiar from a wide variety of text editors, where holding `shift` while navigating selects all text between the initial cursor position when pressing `shift` and the current cursor position. Before this PR can be merged the [sibling PR for reedline](https://github.com/nushell/reedline/pull/689) has to land first. # User-Facing Changes ## Additional `EditCommand`s 1. `SelectAll` 2. `CutSelection` 3. `CopySelection` ## New optional parameter on existing `EditCommand`s All `EditCommand`s of `EditType` `MoveCursor` have a new optional parameter named `select` of type `bool`. If this parameter is not set by a user it is treated as false, which corresponds to their behavior up to now. I am relatively new to `nushell` and as such may not know of existing behavior that might change through this PR. However, I believe there should be none. I come to this conclusion because 1. Existing commands are extended only with an *optional* additional parameter, users who currently use these EditCommands keep their existing behavior if they don't use it. 2. A few new commands are introduced which were previously not valid. 3. The default keybindings specified in `default_config.nu` are untouched. # Tests + Formatting Tests for the new optional parameter for the move commands are included to make sure that they truly are optional and an unused optional parameter conforms to the previous behavior. --- .github/workflows/ci.yml | 6 +- Cargo.lock | 317 +++++++++++++++++- Cargo.toml | 18 +- crates/nu-cli/src/reedline_config.rs | 164 ++++++++- crates/nu-cli/src/repl.rs | 5 +- .../src/sample_config/default_config.nu | 28 ++ 6 files changed, 506 insertions(+), 32 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e061e6f5a4070..49edea282193d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -63,6 +63,10 @@ jobs: platform: [windows-latest, macos-latest, ubuntu-20.04] feature: [default, dataframe, extra] include: + # linux CI cannot handle clipboard feature + - default-flags: "" + - platform: ubuntu-20.04 + default-flags: "--no-default-features --features=default-no-clipboard" - feature: default flags: "" - feature: dataframe @@ -90,7 +94,7 @@ jobs: rustflags: "" - name: Tests - run: cargo test --workspace --profile ci --exclude nu_plugin_* ${{ matrix.flags }} + run: cargo test --workspace --profile ci --exclude nu_plugin_* ${{ matrix.default-flags }} ${{ matrix.flags }} - name: Check for clean repo shell: bash diff --git a/Cargo.lock b/Cargo.lock index ba68fe48259f8..ebf05dc5d1f59 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -160,6 +160,24 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "arboard" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aafb29b107435aa276664c1db8954ac27a6e105cdad3c88287a199eb0e313c08" +dependencies = [ + "clipboard-win", + "log", + "objc", + "objc-foundation", + "objc_id", + "parking_lot", + "thiserror", + "winapi", + "wl-clipboard-rs", + "x11rb", +] + [[package]] name = "argminmax" version = "0.6.1" @@ -385,6 +403,12 @@ dependencies = [ "serde", ] +[[package]] +name = "block" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" + [[package]] name = "block-buffer" version = "0.10.4" @@ -502,7 +526,7 @@ dependencies = [ "codepage", "encoding_rs", "log", - "quick-xml", + "quick-xml 0.31.0", "serde", "zip", ] @@ -688,6 +712,17 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" +[[package]] +name = "clipboard-win" +version = "4.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7191c27c2357d9b7ef96baac1773290d4ca63b24205b82a3fd8a0637afcf0362" +dependencies = [ + "error-code", + "str-buf", + "winapi", +] + [[package]] name = "codepage" version = "0.1.1" @@ -889,7 +924,7 @@ dependencies = [ "autocfg", "cfg-if", "crossbeam-utils", - "memoffset", + "memoffset 0.9.0", "scopeguard", ] @@ -1004,7 +1039,7 @@ version = "3.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "82e95fbd621905b854affdc67943b043a0fbb6ed7385fd5a25650d19a8a6cfdf" dependencies = [ - "nix", + "nix 0.27.1", "windows-sys 0.48.0", ] @@ -1030,6 +1065,17 @@ dependencies = [ "powerfmt", ] +[[package]] +name = "derive-new" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3418329ca0ad70234b9735dc4ceed10af4df60eff9c8e7b06cb5e520d92c3535" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "derive_more" version = "0.99.17" @@ -1096,6 +1142,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "dlib" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" +dependencies = [ + "libloading", +] + [[package]] name = "dlv-list" version = "0.5.2" @@ -1111,6 +1166,12 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" +[[package]] +name = "downcast-rs" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" + [[package]] name = "dtoa" version = "1.0.9" @@ -1234,6 +1295,16 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "error-code" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64f18991e7bf11e7ffee451b5318b5c1a73c52d0d0ada6e5a3017c8c1ced6a21" +dependencies = [ + "libc", + "str-buf", +] + [[package]] name = "ethnum" version = "1.5.0" @@ -1315,6 +1386,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + [[package]] name = "flate2" version = "1.0.28" @@ -1518,6 +1595,16 @@ dependencies = [ "version_check", ] +[[package]] +name = "gethostname" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb65d4ba3173c56a500b555b532f72c42e8d1fe64962b518897f8959fae2c177" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "getrandom" version = "0.2.11" @@ -2364,6 +2451,15 @@ dependencies = [ "libc", ] +[[package]] +name = "memoffset" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +dependencies = [ + "autocfg", +] + [[package]] name = "memoffset" version = "0.9.0" @@ -2519,6 +2615,19 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" +[[package]] +name = "nix" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" +dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "libc", + "memoffset 0.7.1", + "pin-utils", +] + [[package]] name = "nix" version = "0.27.1" @@ -2601,7 +2710,7 @@ dependencies = [ "log", "miette", "mimalloc", - "nix", + "nix 0.27.1", "nu-ansi-term", "nu-cli", "nu-cmd-base", @@ -2808,7 +2917,7 @@ dependencies = [ "mime_guess", "mockito", "native-tls", - "nix", + "nix 0.27.1", "notify-debouncer-full", "nu-ansi-term", "nu-cmd-base", @@ -2836,7 +2945,7 @@ dependencies = [ "percent-encoding", "print-positions", "procfs", - "quick-xml", + "quick-xml 0.31.0", "quickcheck", "quickcheck_macros", "rand", @@ -3033,7 +3142,7 @@ dependencies = [ "libproc", "log", "mach2", - "nix", + "nix 0.27.1", "ntapi", "once_cell", "procfs", @@ -3318,6 +3427,26 @@ dependencies = [ "malloc_buf", ] +[[package]] +name = "objc-foundation" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9" +dependencies = [ + "block", + "objc", + "objc_id", +] + +[[package]] +name = "objc_id" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b" +dependencies = [ + "objc", +] + [[package]] name = "object" version = "0.32.1" @@ -3575,6 +3704,16 @@ dependencies = [ "sha2", ] +[[package]] +name = "petgraph" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" +dependencies = [ + "fixedbitset", + "indexmap", +] + [[package]] name = "phf" version = "0.10.1" @@ -4222,6 +4361,15 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" +[[package]] +name = "quick-xml" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eff6510e86862b57b210fd8cbe8ed3f0d7d600b9c2863cd4549a2e033c66e956" +dependencies = [ + "memchr", +] + [[package]] name = "quick-xml" version = "0.31.0" @@ -4369,8 +4517,9 @@ dependencies = [ [[package]] name = "reedline" version = "0.28.0" -source = "git+https://github.com/nushell/reedline.git?branch=main#dc27ed8ff4746386489dc25f70ea5aa613f540c0" +source = "git+https://github.com/nushell/reedline?branch=main#2f3eb3e82f30ce3b1bb3f2b826071ec8cc278687" dependencies = [ + "arboard", "chrono", "crossterm", "fd-lock", @@ -4665,6 +4814,12 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + [[package]] name = "scopeguard" version = "1.2.0" @@ -5063,6 +5218,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "str-buf" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e08d8363704e6c71fc928674353e6b7c23dcea9d82d7012c8faf2a3a025f8d0" + [[package]] name = "str_indices" version = "0.4.3" @@ -5600,6 +5761,20 @@ dependencies = [ "windows 0.44.0", ] +[[package]] +name = "tree_magic_mini" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91adfd0607cacf6e4babdb870e9bec4037c1c4b151cfd279ccefc5e0c7feaa6d" +dependencies = [ + "bytecount", + "fnv", + "lazy_static", + "nom", + "once_cell", + "petgraph", +] + [[package]] name = "try-lock" version = "0.2.4" @@ -5836,7 +6011,7 @@ dependencies = [ "dunce", "glob", "libc", - "nix", + "nix 0.27.1", "once_cell", "os_display", "uucore_procs", @@ -6036,6 +6211,79 @@ dependencies = [ "walkdir", ] +[[package]] +name = "wayland-backend" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19152ddd73f45f024ed4534d9ca2594e0ef252c1847695255dae47f34df9fbe4" +dependencies = [ + "cc", + "downcast-rs", + "nix 0.26.4", + "scoped-tls", + "smallvec", + "wayland-sys", +] + +[[package]] +name = "wayland-client" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ca7d52347346f5473bf2f56705f360e8440873052e575e55890c4fa57843ed3" +dependencies = [ + "bitflags 2.4.1", + "nix 0.26.4", + "wayland-backend", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e253d7107ba913923dc253967f35e8561a3c65f914543e46843c88ddd729e21c" +dependencies = [ + "bitflags 2.4.1", + "wayland-backend", + "wayland-client", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols-wlr" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad1f61b76b6c2d8742e10f9ba5c3737f6530b4c243132c2a2ccc8aa96fe25cd6" +dependencies = [ + "bitflags 2.4.1", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-scanner", +] + +[[package]] +name = "wayland-scanner" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb8e28403665c9f9513202b7e1ed71ec56fde5c107816843fb14057910b2c09c" +dependencies = [ + "proc-macro2", + "quick-xml 0.30.0", + "quote", +] + +[[package]] +name = "wayland-sys" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15a0c8eaff5216d07f226cb7a549159267f3467b289d9a2e52fd3ef5aae2b7af" +dependencies = [ + "dlib", + "log", + "pkg-config", +] + [[package]] name = "web-sys" version = "0.3.66" @@ -6105,6 +6353,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "winapi-wsapoll" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c17110f57155602a80dca10be03852116403c9ff3cd25b079d666f2aa3df6e" +dependencies = [ + "winapi", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" @@ -6375,6 +6632,48 @@ dependencies = [ "version_check", ] +[[package]] +name = "wl-clipboard-rs" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57af79e973eadf08627115c73847392e6b766856ab8e3844a59245354b23d2fa" +dependencies = [ + "derive-new", + "libc", + "log", + "nix 0.26.4", + "os_pipe", + "tempfile", + "thiserror", + "tree_magic_mini", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-protocols-wlr", +] + +[[package]] +name = "x11rb" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1641b26d4dec61337c35a1b1aaf9e3cba8f46f0b43636c609ab0291a648040a" +dependencies = [ + "gethostname", + "nix 0.26.4", + "winapi", + "winapi-wsapoll", + "x11rb-protocol", +] + +[[package]] +name = "x11rb-protocol" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82d6c3f9a0fb6701fab8f6cea9b0c0bd5d6876f1f89f7fada07e558077c344bc" +dependencies = [ + "nix 0.26.4", +] + [[package]] name = "xattr" version = "1.0.1" diff --git a/Cargo.toml b/Cargo.toml index 363d6f0e61ac5..cec40c98a07d6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,7 +57,9 @@ nu-cli = { path = "./crates/nu-cli", version = "0.89.1" } nu-color-config = { path = "./crates/nu-color-config", version = "0.89.1" } nu-cmd-base = { path = "./crates/nu-cmd-base", version = "0.89.1" } nu-cmd-lang = { path = "./crates/nu-cmd-lang", version = "0.89.1" } -nu-cmd-dataframe = { path = "./crates/nu-cmd-dataframe", version = "0.89.1", features = ["dataframe"], optional = true } +nu-cmd-dataframe = { path = "./crates/nu-cmd-dataframe", version = "0.89.1", features = [ + "dataframe", +], optional = true } nu-cmd-extra = { path = "./crates/nu-cmd-extra", version = "0.89.1", optional = true } nu-command = { path = "./crates/nu-command", version = "0.89.1" } nu-engine = { path = "./crates/nu-engine", version = "0.89.1" } @@ -120,7 +122,16 @@ plugin = [ "nu-protocol/plugin", "nu-engine/plugin", ] -default = ["plugin", "which-support", "trash-support", "sqlite", "mimalloc"] +default = ["default-no-clipboard", "system-clipboard"] +# Enables convenient omitting of the system-clipboard feature, as it leads to problems in ci on linux +# See https://github.com/nushell/nushell/pull/11535 +default-no-clipboard = [ + "plugin", + "which-support", + "trash-support", + "sqlite", + "mimalloc", +] stable = ["default"] wasi = ["nu-cmd-lang/wasi"] # NOTE: individual features are also passed to `nu-cmd-lang` that uses them to generate the feature matrix in the `version` command @@ -130,6 +141,7 @@ wasi = ["nu-cmd-lang/wasi"] static-link-openssl = ["dep:openssl", "nu-cmd-lang/static-link-openssl"] mimalloc = ["nu-cmd-lang/mimalloc", "dep:mimalloc"] +system-clipboard = ["reedline/system_clipboard"] # Stable (Default) which-support = ["nu-command/which-support", "nu-cmd-lang/which-support"] @@ -172,7 +184,7 @@ bench = false # To use a development version of a dependency please use a global override here # changing versions in each sub-crate of the workspace is tedious [patch.crates-io] -reedline = { git = "https://github.com/nushell/reedline.git", branch = "main" } +reedline = { git = "https://github.com/nushell/reedline", branch = "main" } # nu-ansi-term = {git = "https://github.com/nushell/nu-ansi-term.git", branch = "main"} # uu_cp = { git = "https://github.com/uutils/coreutils.git", branch = "main" } diff --git a/crates/nu-cli/src/reedline_config.rs b/crates/nu-cli/src/reedline_config.rs index efd54d597d693..9ab6f4a13865f 100644 --- a/crates/nu-cli/src/reedline_config.rs +++ b/crates/nu-cli/src/reedline_config.rs @@ -861,22 +861,82 @@ fn edit_from_record( span: Span, ) -> Result { let edit = match name { - "movetostart" => EditCommand::MoveToStart, - "movetolinestart" => EditCommand::MoveToLineStart, - "movetoend" => EditCommand::MoveToEnd, - "movetolineend" => EditCommand::MoveToLineEnd, - "moveleft" => EditCommand::MoveLeft, - "moveright" => EditCommand::MoveRight, - "movewordleft" => EditCommand::MoveWordLeft, - "movebigwordleft" => EditCommand::MoveBigWordLeft, - "movewordright" => EditCommand::MoveWordRight, - "movewordrightend" => EditCommand::MoveWordRightEnd, - "movebigwordrightend" => EditCommand::MoveBigWordRightEnd, - "movewordrightstart" => EditCommand::MoveWordRightStart, - "movebigwordrightstart" => EditCommand::MoveBigWordRightStart, + "movetostart" => EditCommand::MoveToStart { + select: extract_value("select", record, span) + .and_then(|value| value.as_bool()) + .unwrap_or(false), + }, + "movetolinestart" => EditCommand::MoveToLineStart { + select: extract_value("select", record, span) + .and_then(|value| value.as_bool()) + .unwrap_or(false), + }, + + "movetoend" => EditCommand::MoveToEnd { + select: extract_value("select", record, span) + .and_then(|value| value.as_bool()) + .unwrap_or(false), + }, + "movetolineend" => EditCommand::MoveToLineEnd { + select: extract_value("select", record, span) + .and_then(|value| value.as_bool()) + .unwrap_or(false), + }, + "moveleft" => EditCommand::MoveLeft { + select: extract_value("select", record, span) + .and_then(|value| value.as_bool()) + .unwrap_or(false), + }, + "moveright" => EditCommand::MoveRight { + select: extract_value("select", record, span) + .and_then(|value| value.as_bool()) + .unwrap_or(false), + }, + "movewordleft" => EditCommand::MoveWordLeft { + select: extract_value("select", record, span) + .and_then(|value| value.as_bool()) + .unwrap_or(false), + }, + "movebigwordleft" => EditCommand::MoveBigWordLeft { + select: extract_value("select", record, span) + .and_then(|value| value.as_bool()) + .unwrap_or(false), + }, + "movewordright" => EditCommand::MoveWordRight { + select: extract_value("select", record, span) + .and_then(|value| value.as_bool()) + .unwrap_or(false), + }, + "movewordrightend" => EditCommand::MoveWordRightEnd { + select: extract_value("select", record, span) + .and_then(|value| value.as_bool()) + .unwrap_or(false), + }, + "movebigwordrightend" => EditCommand::MoveBigWordRightEnd { + select: extract_value("select", record, span) + .and_then(|value| value.as_bool()) + .unwrap_or(false), + }, + "movewordrightstart" => EditCommand::MoveWordRightStart { + select: extract_value("select", record, span) + .and_then(|value| value.as_bool()) + .unwrap_or(false), + }, + "movebigwordrightstart" => EditCommand::MoveBigWordRightStart { + select: extract_value("select", record, span) + .and_then(|value| value.as_bool()) + .unwrap_or(false), + }, "movetoposition" => { let value = extract_value("value", record, span)?; - EditCommand::MoveToPosition(value.as_int()? as usize) + let select = extract_value("select", record, span) + .and_then(|value| value.as_bool()) + .unwrap_or(false); + + EditCommand::MoveToPosition { + position: value.as_int()? as usize, + select, + } } "insertchar" => { let value = extract_value("value", record, span)?; @@ -928,12 +988,18 @@ fn edit_from_record( "moverightuntil" => { let value = extract_value("value", record, span)?; let char = extract_char(value, config)?; - EditCommand::MoveRightUntil(char) + let select = extract_value("select", record, span) + .and_then(|value| value.as_bool()) + .unwrap_or(false); + EditCommand::MoveRightUntil { c: char, select } } "moverightbefore" => { let value = extract_value("value", record, span)?; let char = extract_char(value, config)?; - EditCommand::MoveRightBefore(char) + let select = extract_value("select", record, span) + .and_then(|value| value.as_bool()) + .unwrap_or(false); + EditCommand::MoveRightBefore { c: char, select } } "cutleftuntil" => { let value = extract_value("value", record, span)?; @@ -948,14 +1014,23 @@ fn edit_from_record( "moveleftuntil" => { let value = extract_value("value", record, span)?; let char = extract_char(value, config)?; - EditCommand::MoveLeftUntil(char) + let select = extract_value("select", record, span) + .and_then(|value| value.as_bool()) + .unwrap_or(false); + EditCommand::MoveLeftUntil { c: char, select } } "moveleftbefore" => { let value = extract_value("value", record, span)?; let char = extract_char(value, config)?; - EditCommand::MoveLeftBefore(char) + let select = extract_value("select", record, span) + .and_then(|value| value.as_bool()) + .unwrap_or(false); + EditCommand::MoveLeftBefore { c: char, select } } "complete" => EditCommand::Complete, + "cutselection" => EditCommand::CutSelection, + "copyselection" => EditCommand::CopySelection, + "selectall" => EditCommand::SelectAll, e => { return Err(ShellError::UnsupportedConfigValue { expected: "reedline EditCommand".to_string(), @@ -1109,4 +1184,57 @@ mod test { let b = EventType::try_from_record(&event, span); assert!(matches!(b, Err(ShellError::MissingConfigValue { .. }))); } + + #[test] + fn test_move_without_optional_select() { + let event = record! { + "edit" => Value::test_string("moveleft") + }; + let event = Value::test_record(event); + let config = Config::default(); + + let parsed_event = parse_event(&event, &config).unwrap(); + assert_eq!( + parsed_event, + Some(ReedlineEvent::Edit(vec![EditCommand::MoveLeft { + select: false + }])) + ); + } + + #[test] + fn test_move_with_select_false() { + let event = record! { + "edit" => Value::test_string("moveleft"), + "select" => Value::test_bool(false) + }; + let event = Value::test_record(event); + let config = Config::default(); + + let parsed_event = parse_event(&event, &config).unwrap(); + assert_eq!( + parsed_event, + Some(ReedlineEvent::Edit(vec![EditCommand::MoveLeft { + select: false + }])) + ); + } + + #[test] + fn test_move_with_select_true() { + let event = record! { + "edit" => Value::test_string("moveleft"), + "select" => Value::test_bool(true) + }; + let event = Value::test_record(event); + let config = Config::default(); + + let parsed_event = parse_event(&event, &config).unwrap(); + assert_eq!( + parsed_event, + Some(ReedlineEvent::Edit(vec![EditCommand::MoveLeft { + select: true + }])) + ); + } } diff --git a/crates/nu-cli/src/repl.rs b/crates/nu-cli/src/repl.rs index b93eb406bc747..c4d04bf3dce40 100644 --- a/crates/nu-cli/src/repl.rs +++ b/crates/nu-cli/src/repl.rs @@ -657,7 +657,10 @@ pub fn evaluate_repl( line_editor.run_edit_commands(&[ EditCommand::Clear, EditCommand::InsertString(repl.buffer.to_string()), - EditCommand::MoveToPosition(repl.cursor_pos), + EditCommand::MoveToPosition { + position: repl.cursor_pos, + select: false, + }, ]); repl.buffer = "".to_string(); repl.cursor_pos = 0; diff --git a/crates/nu-utils/src/sample_config/default_config.nu b/crates/nu-utils/src/sample_config/default_config.nu index b12057d635989..4af77b6d8a380 100644 --- a/crates/nu-utils/src/sample_config/default_config.nu +++ b/crates/nu-utils/src/sample_config/default_config.nu @@ -760,5 +760,33 @@ $env.config = { mode: emacs event: {edit: capitalizechar} } + { + name: copy_selection + modifier: control_shift + keycode: char_c + mode: emacs + event: { edit: copyselection } + } + { + name: cut_selection + modifier: control_shift + keycode: char_x + mode: emacs + event: { edit: cutselection } + } + { + name: select_all + modifier: control_shift + keycode: char_a + mode: emacs + event: { edit: selectall } + } + { + name: paste + modifier: control_shift + keycode: char_v + mode: emacs + event: { edit: pastecutbufferbefore } + } ] }