From e7a4af14cd8563d043690c613c7a5624fd0838ca 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 e061e6f5a4..49edea2821 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 ba68fe4825..ebf05dc5d1 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 363d6f0e61..cec40c98a0 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 efd54d597d..9ab6f4a138 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 b93eb406bc..c4d04bf3dc 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 b12057d635..4af77b6d8a 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 } + } ] }