mirror of
https://github.com/zellij-org/zellij.git
synced 2024-11-22 22:26:54 +03:00
feat(terminal): search panes (#1521)
* WIP: First draft of searching in panes. * Add ability to highlight search-results in viewport and move forwards/backwards * Clear search results when leaving search * Search newly scrolled in lines and have live-search when entering search-term * search_forward/backward() now doesn't get the needle again, since we already know it * Use red and yellow from theme. No idea if we should introduce new 'search'-colors * Implement moving the viewport for searches outside the current one. * Implement hacky case-insensitivity (ASCII only at the moment) * Implement wrap-search and prepare infrastructure for whole-word search * Add a bunch of tests and an embarrasing amount of bugfixes * Remember search selection when toggling case-sensitivity (if possible) * New tab integration tests and make search work with floating panes * Make highlights work with resize (not keeping the active-selection in most cases) * Switch the search-algo a bit in order to make multi-line search work * Don't forget active selection when nothing more is found, reflow found selections and scroll correctly * Make all search-related function calls in plugin-pane No-ops * Activate whole word search (ASCII only) * Run cargo fmt * Make clippy happy * Remove unneeded transferred_rows_count * Remove boilerplate and use macro instead * Add explanatory comments * Move search-related functions into SearchResults impl and try to remove duplicate code * Move clearing of search-results upon mode-switch to appropriate place * Jump to the first occurence while typing (EnterSearch), if none is found in the current viewport * Always show needle and also show search modifiers in pane title * Integration tests now use correct InputMode, so we can test the pane title when doing searches * Move no-op implementation of search-functions from plugin-pane to pane-trait * Move SearchResult to its own file * Try to clean up search_row() a bit * Make clippy happy * fix: various typos (#1553) Because they were wrong. * flake.lock: Update (#1554) Flake lock file updates: • Updated input 'crate2nix': 'github:kolloch/crate2nix/805cdaf084c859c2ea0c084b74f4527b0483f6aa' (2022-06-17) → 'github:kolloch/crate2nix/91f333aca414ee346bc5bdea76fe9938f73a15f9' (2022-07-01) • Updated input 'flake-utils': 'github:numtide/flake-utils/1ed9fb1935d260de5fe1c2f7ee0ebaae17ed2fa1' (2022-05-30) → 'github:numtide/flake-utils/bee6a7250dd1b01844a2de7e02e4df7d8a0a206c' (2022-06-24) • Updated input 'nixpkgs': 'github:nixos/nixpkgs/3d7435c638baffaa826b85459df0fff47f12317d' (2022-06-16) → 'github:nixos/nixpkgs/0ea7a8f1b939d74e5df8af9a8f7342097cdf69eb' (2022-07-02) • Updated input 'rust-overlay': 'github:oxalica/rust-overlay/da04f39d50ad2844e97a44015048c2510ca06c2f' (2022-06-18) → 'github:oxalica/rust-overlay/bbba5e73a21c8c67d5fe1d4d8b3fde60ab6946cd' (2022-07-03) * fix: fallback to default values when terminal rows/cols are 0 (#1552) * fix: fallback to default values when terminal rows/cols = 0 * increase retry_pause for failing test * e2e: load fixtures with cat * use variable for fixture path * docs(changelog): fix 0 rows or cols crash * fix(ci): clippy (#1559) Install `cargo-make` explicitly in the workflow, even tough it should be cached from the previous steps. There are some corner cases in which gh messes the caching up and can't access it. * add(nix): add `compact-bar` to the flake outputs (#1560) The compact bar wasn't an output yet. * refactor(crates): move shared contents from zellij tile to zellij utils (#1541) * zellij-tile: Move `data` to zellij-utils The rationale behind this is that all components of zellij access the data structures defined in this module, as they define some of the most basic types in the application. However, so far zellij-tile is treated like a separate crate from the rest of the program in that it is the only one that doesn't have access to `zellij-utils`, which contains a lot of other data structures used throughout zellij. This poses issues as discussed in https://github.com/zellij-org/zellij/pull/1242 and is one of the reasons why the keybindings in the status bar default plugin can't be updated dynamically. It is also the main reason for why the keybindings are currently passed to the plugin as strings: The plugins only have access to `zellij-tile`, but since this is a dependency of `zellij-utils`, it can't import `zellij-utils` to access the keybindings. Other weird side-effect are that in some places `server` and `client` have to access the `zellij-tile` contents "through" `zellij-utils`, as in `use zellij_utils::zellij_tile::prelude::*`. By moving these central data structures to one common shared crate (`zellij-utils`), `zellij-tile` will be enabled to import `zellij-utils` like `screen` and `client` already do. This will, next to other things, allow dropping a lot of `std::fmt::Fmt` impls needed to convert core data structures into strings and as a consequence, a lot of string parsing in the first place. * utils: Integrate new `data` module, bump rust ver Integrates the `data` module that was previously part of `zellij-tile` to allow sharing the contained data structures between all components of zellij. This allows `zellij-tile` to use `utils` as a dependency. However, since `tile` is build against the wasm target, it cannot include all of `zellij-utils`, since a lot of dependencies there cannot compile with `wasm` as target (Examples include: termwiz, log4rs, async-std). Thus we make all the dependencies that cannot compile against `wasm` optional and introduce a new feature `full` that will compile the crate with all dependencies. Along with this, modify `lib.rs` to include most of the data structures only when compiling against the `full` feature. This makes the compiles of `zellij-tile` lighter, as it doesn't include all of `utils`. As a side effect, due to the dependency notation for the optional dependencies (See https://doc.rust-lang.org/cargo/reference/features.html#optional-dependencies), we bump the rust toolchain version to 1.60.0. * tile: Import `data` from zellij-utils Add `zellij-utils` as a dependency to `zellij-tile` and allow us access to the `data` module defined there. Update the re-export in the `prelude` such that from all of the plugins points of view *absolutely nothing changes*. * utils: Fix `data` module dependency Since the `data` module has been migrated from `zellij-tile` to `zellij-utils`, we import it from `zellij-utils` directly now. Also unify the imports for the `data` module members: We import all of the through `data::` now, not through a mixture of `data::` and `prelude::`. * client: Fix `data` module dependency Since the `data` module has been migrated from `zellij-tile` to `zellij-utils`, we import it from `zellij-utils` directly now. Also unify the imports for the `data` module members: We import all of the through `data::` now, not through a mixture of `data::` and `prelude::`. Add the "full" feature flag to the `zellij-utils` dependency so it includes all the components we need. * server: Fix `data` module dependency Since the `data` module has been migrated from `zellij-tile` to `zellij-utils`, we import it from `zellij-utils` directly now. Also unify the imports for the `data` module members: We import all of the through `data::` now, not through a mixture of `data::` and `prelude::`. Add the "full" feature flag to the `zellij-utils` dependency so it includes all the components we need. * tests: Fix `data` module dependency Since the `data` module has been migrated from `zellij-tile` to `zellij-utils`, we import it from `zellij-utils` directly now. * utils: Remove "full" feature in favor of conditional compilation using `target_family`. Replace the rust 1.60 method of specifying optional dependencies based on features and optionally include the dependencies only when not building for wasm instead. (I.e. `cfg(not(target_family = "wasm"))`) * cargo: Update module dependencies since `client`, `server` and `tile` now all depend on `utils` only. * docs(changelog): crate refactor * fix: typo (#1567) * feat(terminal): sixel support (#1557) * work * work * work * work * work * more work * work * work * work * hack around stdin repeater * refactor(sixel): rename sixel structs * feat(sixel): render text above images * fix(sixel): reap images once they're past the end of the scrollbuffer * fix(sixel): display images in the middle of the line * fix(sixel): render crash * fix(sixel): react to SIGWINCH * fix(sixel): behave properly in alternate screen mode * fix(sixel): reap images on terminal reset * feat(sixel): handle DECSDM * fix(terminal): properly respond to XTSMGRAPHICS and device attributes with Sixel * Add comment * fix(sixel): hack for unknown event overflow until we fix the api * feat(input): query terminal for all OSC 4 colors and respond to them in a buggy way * fix(sixel): do not render corrupted image * feat(input): improve STDIN queries * fix(client): mistake in clear terminal attributes string * fix(ansi): report correct number of supported color registers * fix(sixel): reap images that are completely covered * style(comment): fix name * test(sixel): infra * test(sixel): cases and fixes * fix(sixel): forward dcs bytes to sixel parser * refactor(client): ansi stdin parser * refactor(output): cleanup * some refactorings * fix test * refactor(grid): sixel-grid / sixel-image-store * refactor(grid): grid debug method * refactor(grid): move various logic to sixel.rs * refactor(grid): remove unused methods * fix(sixel): work with multiple users * refactor(pane): remove unused z_index * style(fmt): prepend unused variable * style(fmt): rustfmt * fix(tests): various apis * chore(dependencies): use published version of sixel crates * style(fmt): rustfmt * style(fmt): rustfmt * style(lint): make clippy happy * style(lint): make clippy happy... again * style(lint): make clippy happy... again (chapter 2) * style(comment): remove unused * fix(colors): export COLORTERM and respond to XTVERSION * fix(test): color register count * fix(stdin): adjust STDIN sleep times * docs(changelog): sixel support * flake.lock: Update (#1575) Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * fix(ci): add new rust toolchain location to action (#1576) * rust-toolchain: Update (#1578) Co-authored-by: a-kenji <a-kenji@users.noreply.github.com> * chore(nix): hide `nix` directory (#1579) * chore(gblame): add move to git-blame-ignore-revs This is not relevant for `git blame` messages. * chore(docs): add more matrix links (#1581) * fix: add usage comment to fish shell auto-start snippet (#1574) (#1583) * docs(changelog): add usage comment to fish script * Refactor match session name (#1582) * docs(changelog): refactor get session name (#1582) * fix(cli): let the exit message be different when detaching (#1573) * Let the exit message be different when detaching This patch changes the exit message printed to the user, so the user does not get the impression that they fat-fingered an "exit" instead of what was intended (a detach). For this, the InputHandler::exit() function was refactored, to get the reason as a parameter. As this function is not pub, this is considered okay. Signed-off-by: Matthias Beyer <mail@beyermatthias.de> * Change detach message This patch changes the detach message to be more in line with the other messages zellij displays to the user. Signed-off-by: Matthias Beyer <mail@beyermatthias.de> * docs(changelog): detach message * perf(terminal): better responsiveness (#1585) * performance(pty): only buffer terminal bytes when screen thread is backed up * style(fmt): rustfmt * docs(changelog): performance improvement * style(fmt): rustfmt * fix(search): adjust foreground color for better readability * style(fmt): rustfmt * test(e2e): update snapshots from SCROLL to SEARCH * Rename search directions to up/down * Rename search-functions in tests as well * Move all search-related functions out of grid.rs and into search.rs and reuse as much as possible * Fix bug where searches that fall on the line-ending are highlighting the whole line * Silence clippy on what I think is a false-positive * fix(terminal): persist cursor hide/show through alternate screen (#1586) * fix(terminal): persist cursor hide/show through alternate screen * style(fmt): rustfmt * style(clippy): make clippy happy * docs(changelog): cursor show/hide alternate screen fix * fix(editor): handle editor/visual/configured editor with arguments (#1587) * fix(editor): handle editor/visual/configured editor with arguments * style(fmt): rustfmt * docs(changelog): editor with arguments * fix(ci): quoting issues (#1589) * fix(mouse): avoid forwarding click events on pane border (#1584) * if left click is on pane border do not forward to application * properly handle frames * fix comment * fix another comment * add tests, fix edge case * docs(changelog): mouse click on pane frame fix * flake.lock: Update (#1592) Flake lock file updates: • Updated input 'crate2nix': 'github:kolloch/crate2nix/2d20dec4ae330f39b0bebeb8eb4a201b58d2b82c' (2022-07-09) → 'github:kolloch/crate2nix/45d97c7ce62c3d53954743057ceb32e483c31acd' (2022-07-12) • Updated input 'nixpkgs': 'github:nixos/nixpkgs/b39924fc7764c08ae3b51beef9a3518c414cdb7d' (2022-07-08) → 'github:nixos/nixpkgs/4a01ca36d6bfc133bc617e661916a81327c9bbc8' (2022-07-14) • Updated input 'rust-overlay': 'github:oxalica/rust-overlay/3dfc78e42a285caaf83633224a42e7fb7dde191b' (2022-07-10) → 'github:oxalica/rust-overlay/2cd36d4aef875867ee1d7963541ccb3ae50b358c' (2022-07-16) Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * fix(search): clear search when entering input in non-search-mode * fix(search): handle searching in updating viewport Co-authored-by: Martin Sirringhaus <> Co-authored-by: a-kenji <aks.kenji@protonmail.com> Co-authored-by: Thomas Linford <tlinford@users.noreply.github.com> Co-authored-by: Aram Drevekenin <aram@poor.dev> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: a-kenji <a-kenji@users.noreply.github.com> Co-authored-by: Tassilo Horn <tsdh@gnu.org> Co-authored-by: Jae-Heon Ji <32578710+jaeheonji@users.noreply.github.com> Co-authored-by: Matthias Beyer <mail@beyermatthias.de>
This commit is contained in:
parent
dd08fec570
commit
bae1548495
@ -20,7 +20,7 @@ enum CtrlKeyAction {
|
||||
Pane,
|
||||
Tab,
|
||||
Resize,
|
||||
Scroll,
|
||||
Search,
|
||||
Quit,
|
||||
Session,
|
||||
Move,
|
||||
@ -40,7 +40,7 @@ impl CtrlKeyShortcut {
|
||||
CtrlKeyAction::Pane => String::from("PANE"),
|
||||
CtrlKeyAction::Tab => String::from("TAB"),
|
||||
CtrlKeyAction::Resize => String::from("RESIZE"),
|
||||
CtrlKeyAction::Scroll => String::from("SCROLL"),
|
||||
CtrlKeyAction::Search => String::from("SEARCH"),
|
||||
CtrlKeyAction::Quit => String::from("QUIT"),
|
||||
CtrlKeyAction::Session => String::from("SESSION"),
|
||||
CtrlKeyAction::Move => String::from("MOVE"),
|
||||
@ -52,7 +52,7 @@ impl CtrlKeyShortcut {
|
||||
CtrlKeyAction::Pane => 'p',
|
||||
CtrlKeyAction::Tab => 't',
|
||||
CtrlKeyAction::Resize => 'n',
|
||||
CtrlKeyAction::Scroll => 's',
|
||||
CtrlKeyAction::Search => 's',
|
||||
CtrlKeyAction::Quit => 'q',
|
||||
CtrlKeyAction::Session => 'o',
|
||||
CtrlKeyAction::Move => 'h',
|
||||
@ -328,7 +328,7 @@ pub fn ctrl_keys(help: &ModeInfo, max_len: usize, separator: &str) -> LinePart {
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::Disabled, CtrlKeyAction::Tab),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::Disabled, CtrlKeyAction::Resize),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::Disabled, CtrlKeyAction::Move),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::Disabled, CtrlKeyAction::Scroll),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::Disabled, CtrlKeyAction::Search),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::Disabled, CtrlKeyAction::Session),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::Disabled, CtrlKeyAction::Quit),
|
||||
],
|
||||
@ -343,7 +343,7 @@ pub fn ctrl_keys(help: &ModeInfo, max_len: usize, separator: &str) -> LinePart {
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Tab),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::Selected, CtrlKeyAction::Resize),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Move),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::UnselectedAlternate, CtrlKeyAction::Scroll),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::UnselectedAlternate, CtrlKeyAction::Search),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Session),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::UnselectedAlternate, CtrlKeyAction::Quit),
|
||||
],
|
||||
@ -358,7 +358,7 @@ pub fn ctrl_keys(help: &ModeInfo, max_len: usize, separator: &str) -> LinePart {
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Tab),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::UnselectedAlternate, CtrlKeyAction::Resize),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Move),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::UnselectedAlternate, CtrlKeyAction::Scroll),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::UnselectedAlternate, CtrlKeyAction::Search),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Session),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::UnselectedAlternate, CtrlKeyAction::Quit),
|
||||
],
|
||||
@ -373,14 +373,14 @@ pub fn ctrl_keys(help: &ModeInfo, max_len: usize, separator: &str) -> LinePart {
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::Selected, CtrlKeyAction::Tab),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::UnselectedAlternate, CtrlKeyAction::Resize),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Move),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::UnselectedAlternate, CtrlKeyAction::Scroll),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::UnselectedAlternate, CtrlKeyAction::Search),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Session),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::UnselectedAlternate, CtrlKeyAction::Quit),
|
||||
],
|
||||
colored_elements,
|
||||
separator,
|
||||
),
|
||||
InputMode::Scroll => key_indicators(
|
||||
InputMode::EnterSearch | InputMode::Scroll | InputMode::Search => key_indicators(
|
||||
max_len,
|
||||
&[
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Lock),
|
||||
@ -388,7 +388,7 @@ pub fn ctrl_keys(help: &ModeInfo, max_len: usize, separator: &str) -> LinePart {
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Tab),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::UnselectedAlternate, CtrlKeyAction::Resize),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Move),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::Selected, CtrlKeyAction::Scroll),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::Selected, CtrlKeyAction::Search),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Session),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::UnselectedAlternate, CtrlKeyAction::Quit),
|
||||
],
|
||||
@ -403,7 +403,7 @@ pub fn ctrl_keys(help: &ModeInfo, max_len: usize, separator: &str) -> LinePart {
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Tab),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::UnselectedAlternate, CtrlKeyAction::Resize),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::Selected, CtrlKeyAction::Move),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::UnselectedAlternate, CtrlKeyAction::Scroll),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::UnselectedAlternate, CtrlKeyAction::Search),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Session),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::UnselectedAlternate, CtrlKeyAction::Quit),
|
||||
],
|
||||
@ -418,7 +418,7 @@ pub fn ctrl_keys(help: &ModeInfo, max_len: usize, separator: &str) -> LinePart {
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Tab),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::UnselectedAlternate, CtrlKeyAction::Resize),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Move),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::UnselectedAlternate, CtrlKeyAction::Scroll),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::UnselectedAlternate, CtrlKeyAction::Search),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Session),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::UnselectedAlternate, CtrlKeyAction::Quit),
|
||||
],
|
||||
@ -433,7 +433,7 @@ pub fn ctrl_keys(help: &ModeInfo, max_len: usize, separator: &str) -> LinePart {
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Tab),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::UnselectedAlternate, CtrlKeyAction::Resize),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Move),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::UnselectedAlternate, CtrlKeyAction::Scroll),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::UnselectedAlternate, CtrlKeyAction::Search),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::Selected, CtrlKeyAction::Session),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::UnselectedAlternate, CtrlKeyAction::Quit),
|
||||
],
|
||||
@ -448,7 +448,7 @@ pub fn ctrl_keys(help: &ModeInfo, max_len: usize, separator: &str) -> LinePart {
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Tab),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::UnselectedAlternate, CtrlKeyAction::Resize),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Move),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::UnselectedAlternate, CtrlKeyAction::Scroll),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::UnselectedAlternate, CtrlKeyAction::Search),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Session),
|
||||
CtrlKeyShortcut::new(CtrlKeyMode::UnselectedAlternate, CtrlKeyAction::Quit),
|
||||
],
|
||||
|
@ -196,6 +196,7 @@ fn full_shortcut_list(help: &ModeInfo, tip: TipFn) -> LinePart {
|
||||
InputMode::Locked => locked_interface_indication(help.style.colors),
|
||||
InputMode::Tmux => full_tmux_mode_indication(help),
|
||||
InputMode::RenamePane => full_shortcut_list_nonstandard_mode(select_pane_shortcut)(help),
|
||||
InputMode::EnterSearch => full_shortcut_list_nonstandard_mode(select_pane_shortcut)(help),
|
||||
_ => full_shortcut_list_nonstandard_mode(confirm_pane_selection)(help),
|
||||
}
|
||||
}
|
||||
@ -225,6 +226,9 @@ fn shortened_shortcut_list(help: &ModeInfo, tip: TipFn) -> LinePart {
|
||||
InputMode::RenamePane => {
|
||||
shortened_shortcut_list_nonstandard_mode(select_pane_shortcut)(help)
|
||||
},
|
||||
InputMode::EnterSearch => {
|
||||
shortened_shortcut_list_nonstandard_mode(select_pane_shortcut)(help)
|
||||
},
|
||||
_ => shortened_shortcut_list_nonstandard_mode(confirm_pane_selection)(help),
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
source: src/tests/e2e/cases.rs
|
||||
assertion_line: 1673
|
||||
assertion_line: 1636
|
||||
expression: last_snapshot
|
||||
---
|
||||
Zellij (e2e-test) Tab #1
|
||||
@ -25,5 +25,5 @@ expression: last_snapshot
|
||||
│ │
|
||||
│ │
|
||||
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SCROLL <o> SESSION <q> QUIT
|
||||
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SEARCH <o> SESSION <q> QUIT
|
||||
Tip: Alt + <n> => new pane. Alt + <←↓↑→ or hjkl> => navigate. Alt + <+-> => resize pane.
|
||||
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
source: src/tests/e2e/cases.rs
|
||||
assertion_line: 558
|
||||
assertion_line: 538
|
||||
expression: last_snapshot
|
||||
---
|
||||
Zellij (e2e-test) Tab #1
|
||||
@ -25,5 +25,5 @@ expression: last_snapshot
|
||||
│ │
|
||||
│ │
|
||||
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SCROLL <o> SESSION <q> QUIT
|
||||
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SEARCH <o> SESSION <q> QUIT
|
||||
Tip: Alt + <n> => new pane. Alt + <←↓↑→ or hjkl> => navigate. Alt + <+-> => resize pane.
|
||||
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
source: src/tests/e2e/cases.rs
|
||||
assertion_line: 498
|
||||
assertion_line: 478
|
||||
expression: last_snapshot
|
||||
---
|
||||
Zellij (e2e-test) Tab #1
|
||||
@ -25,5 +25,5 @@ expression: last_snapshot
|
||||
│ ││ │
|
||||
│ ││ │
|
||||
└──────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘
|
||||
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SCROLL <o> SESSION <q> QUIT
|
||||
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SEARCH <o> SESSION <q> QUIT
|
||||
Tip: Alt + <n> => new pane. Alt + <←↓↑→ or hjkl> => navigate. Alt + <+-> => resize pane.
|
||||
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
source: src/tests/e2e/cases.rs
|
||||
assertion_line: 967
|
||||
assertion_line: 948
|
||||
expression: last_snapshot
|
||||
---
|
||||
Zellij (e2e-test) Tab #1
|
||||
@ -25,5 +25,5 @@ expression: last_snapshot
|
||||
│ ││ │
|
||||
│ ││ │
|
||||
└──────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘
|
||||
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SCROLL <o> SESSION <q> QUIT
|
||||
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SEARCH <o> SESSION <q> QUIT
|
||||
Tip: Alt + <n> => new pane. Alt + <←↓↑→ or hjkl> => navigate. Alt + <+-> => resize pane.
|
||||
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
source: src/tests/e2e/cases.rs
|
||||
assertion_line: 1061
|
||||
assertion_line: 1042
|
||||
expression: last_snapshot
|
||||
---
|
||||
Zellij (e2e-test) Tab #1
|
||||
@ -25,5 +25,5 @@ expression: last_snapshot
|
||||
│ ││ │
|
||||
│ ││ │
|
||||
└──────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘
|
||||
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SCROLL <o> SESSION <q> QUIT
|
||||
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SEARCH <o> SESSION <q> QUIT
|
||||
Tip: Alt + <n> => new pane. Alt + <←↓↑→ or hjkl> => navigate. Alt + <+-> => resize pane.
|
||||
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
source: src/tests/e2e/cases.rs
|
||||
assertion_line: 1757
|
||||
assertion_line: 1720
|
||||
expression: last_snapshot
|
||||
---
|
||||
Zellij (e2e-test) Tab #1 Tab #2 Tab #3 Tab #4 Tab #5 Tab #6 Tab #7 Tab #8 Tab #9
|
||||
@ -25,5 +25,5 @@ expression: last_snapshot
|
||||
│ ││ │
|
||||
│ ││ │
|
||||
└──────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘
|
||||
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SCROLL <o> SESSION <q> QUIT
|
||||
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SEARCH <o> SESSION <q> QUIT
|
||||
Tip: Alt + <n> => new pane. Alt + <←↓↑→ or hjkl> => navigate. Alt + <+-> => resize pane.
|
||||
|
@ -1,7 +1,7 @@
|
||||
---
|
||||
source: src/tests/e2e/cases.rs
|
||||
assertion_line: 803
|
||||
expression: last_snapshot
|
||||
|
||||
---
|
||||
Zellij (e2e-test) Tab #1
|
||||
┌ Pane #1 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||||
@ -25,5 +25,5 @@ expression: last_snapshot
|
||||
│ │
|
||||
│ │
|
||||
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SCROLL <o> SESSION <q> QUIT
|
||||
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SEARCH <o> SESSION <q> QUIT
|
||||
-- INTERFACE LOCKED --
|
||||
|
@ -1,7 +1,7 @@
|
||||
---
|
||||
source: src/tests/e2e/cases.rs
|
||||
assertion_line: 1308
|
||||
expression: second_runner_snapshot
|
||||
|
||||
---
|
||||
Zellij (mirrored_sessions) Tab #1 Tab #2
|
||||
┌ Pane #1 ─────────────────────────────────────────────────┐┌ Pane #2 ─────────────────────────────────────────────────┐
|
||||
@ -25,5 +25,5 @@ expression: second_runner_snapshot
|
||||
│ ││ │
|
||||
│ ││ │
|
||||
└──────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘
|
||||
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SCROLL <o> SESSION <q> QUIT
|
||||
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SEARCH <o> SESSION <q> QUIT
|
||||
<←↓↑→> Move focus / <n> New / <x> Close / <r> Rename / <s> Sync / <Tab> Toggle / <ENTER> Select pane
|
||||
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
source: src/tests/e2e/cases.rs
|
||||
assertion_line: 1344
|
||||
assertion_line: 1307
|
||||
expression: first_runner_snapshot
|
||||
---
|
||||
Zellij (mirrored_sessions) Tab #1 Tab #2
|
||||
@ -25,5 +25,5 @@ expression: first_runner_snapshot
|
||||
│ ││ │
|
||||
│ ││ │
|
||||
└──────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘
|
||||
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SCROLL <o> SESSION <q> QUIT
|
||||
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SEARCH <o> SESSION <q> QUIT
|
||||
Tip: Alt + <n> => new pane. Alt + <←↓↑→ or hjkl> => navigate. Alt + <+-> => resize pane.
|
||||
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
source: src/tests/e2e/cases.rs
|
||||
assertion_line: 1523
|
||||
assertion_line: 1486
|
||||
expression: second_runner_snapshot
|
||||
---
|
||||
Zellij (multiple_users_in_same_pane_and_tab) Tab #1 [ ]
|
||||
@ -25,5 +25,5 @@ expression: second_runner_snapshot
|
||||
│ ││ │
|
||||
│ ││ │
|
||||
└──────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘
|
||||
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SCROLL <o> SESSION <q> QUIT
|
||||
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SEARCH <o> SESSION <q> QUIT
|
||||
Tip: Alt + <n> => new pane. Alt + <←↓↑→ or hjkl> => navigate. Alt + <+-> => resize pane.
|
||||
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
source: src/tests/e2e/cases.rs
|
||||
assertion_line: 1522
|
||||
assertion_line: 1485
|
||||
expression: first_runner_snapshot
|
||||
---
|
||||
Zellij (multiple_users_in_same_pane_and_tab) Tab #1 [ ]
|
||||
@ -25,5 +25,5 @@ expression: first_runner_snapshot
|
||||
│ ││ │
|
||||
│ ││ │
|
||||
└──────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘
|
||||
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SCROLL <o> SESSION <q> QUIT
|
||||
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SEARCH <o> SESSION <q> QUIT
|
||||
Tip: Alt + <n> => new pane. Alt + <←↓↑→ or hjkl> => navigate. Alt + <+-> => resize pane.
|
||||
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
source: src/tests/e2e/cases.rs
|
||||
assertion_line: 1618
|
||||
assertion_line: 1581
|
||||
expression: second_runner_snapshot
|
||||
---
|
||||
Zellij (multiple_users_in_different_tabs) Tab #1 [ ] Tab #2
|
||||
@ -25,5 +25,5 @@ expression: second_runner_snapshot
|
||||
│ │
|
||||
│ │
|
||||
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SCROLL <o> SESSION <q> QUIT
|
||||
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SEARCH <o> SESSION <q> QUIT
|
||||
Tip: Alt + <n> => new pane. Alt + <←↓↑→ or hjkl> => navigate. Alt + <+-> => resize pane.
|
||||
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
source: src/tests/e2e/cases.rs
|
||||
assertion_line: 1617
|
||||
assertion_line: 1580
|
||||
expression: first_runner_snapshot
|
||||
---
|
||||
Zellij (multiple_users_in_different_tabs) Tab #1 Tab #2 [ ]
|
||||
@ -25,5 +25,5 @@ expression: first_runner_snapshot
|
||||
│ │
|
||||
│ │
|
||||
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SCROLL <o> SESSION <q> QUIT
|
||||
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SEARCH <o> SESSION <q> QUIT
|
||||
Tip: Alt + <n> => new pane. Alt + <←↓↑→ or hjkl> => navigate. Alt + <+-> => resize pane.
|
||||
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
source: src/tests/e2e/cases.rs
|
||||
assertion_line: 1433
|
||||
assertion_line: 1396
|
||||
expression: second_runner_snapshot
|
||||
---
|
||||
Zellij (multiple_users_in_same_pane_and_tab) Tab #1 [ ]
|
||||
@ -25,5 +25,5 @@ expression: second_runner_snapshot
|
||||
│ │
|
||||
│ │
|
||||
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SCROLL <o> SESSION <q> QUIT
|
||||
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SEARCH <o> SESSION <q> QUIT
|
||||
Tip: Alt + <n> => new pane. Alt + <←↓↑→ or hjkl> => navigate. Alt + <+-> => resize pane.
|
||||
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
source: src/tests/e2e/cases.rs
|
||||
assertion_line: 1432
|
||||
assertion_line: 1395
|
||||
expression: first_runner_snapshot
|
||||
---
|
||||
Zellij (multiple_users_in_same_pane_and_tab) Tab #1 [ ]
|
||||
@ -25,5 +25,5 @@ expression: first_runner_snapshot
|
||||
│ │
|
||||
│ │
|
||||
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SCROLL <o> SESSION <q> QUIT
|
||||
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SEARCH <o> SESSION <q> QUIT
|
||||
Tip: Alt + <n> => new pane. Alt + <←↓↑→ or hjkl> => navigate. Alt + <+-> => resize pane.
|
||||
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
source: src/tests/e2e/cases.rs
|
||||
assertion_line: 418
|
||||
assertion_line: 398
|
||||
expression: last_snapshot
|
||||
---
|
||||
Zellij (e2e-test) Tab #1 Tab #2
|
||||
@ -25,5 +25,5 @@ expression: last_snapshot
|
||||
│ │
|
||||
│ │
|
||||
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SCROLL <o> SESSION <q> QUIT
|
||||
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SEARCH <o> SESSION <q> QUIT
|
||||
Tip: Alt + <n> => new pane. Alt + <←↓↑→ or hjkl> => navigate. Alt + <+-> => resize pane.
|
||||
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
source: src/tests/e2e/cases.rs
|
||||
assertion_line: 764
|
||||
assertion_line: 744
|
||||
expression: last_snapshot
|
||||
---
|
||||
Zellij (e2e-test) Tab #1
|
||||
@ -25,5 +25,5 @@ expression: last_snapshot
|
||||
│ ││ │
|
||||
│ ││ │
|
||||
└────────────────────────────────────────────────────┘└────────────────────────────────────────────────────────────────┘
|
||||
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SCROLL <o> SESSION <q> QUIT
|
||||
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SEARCH <o> SESSION <q> QUIT
|
||||
Tip: Alt + <n> => new pane. Alt + <←↓↑→ or hjkl> => navigate. Alt + <+-> => resize pane.
|
||||
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
source: src/tests/e2e/cases.rs
|
||||
assertion_line: 276
|
||||
assertion_line: 274
|
||||
expression: last_snapshot
|
||||
---
|
||||
Zellij (e2e-test) Tab #1
|
||||
@ -25,5 +25,5 @@ expression: last_snapshot
|
||||
│ ││line20 │
|
||||
│ ││li█e21 │
|
||||
└──────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘
|
||||
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SCROLL <o> SESSION <q> QUIT
|
||||
<↓↑> Scroll / <PgDn/PgUp> Scroll / <d/u> Scroll / <e> Edit / <ENTER> Select pane
|
||||
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SEARCH <o> SESSION <q> QUIT
|
||||
<↓↑> Scroll / <PgDn/PgUp> Scroll / <d/u> Scroll / <e> Edit / <s> Enter / <ENTER> Select pane
|
||||
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
source: src/tests/e2e/cases.rs
|
||||
assertion_line: 1141
|
||||
assertion_line: 1117
|
||||
expression: last_snapshot
|
||||
---
|
||||
Zellij (e2e-test) Tab #1
|
||||
@ -25,5 +25,5 @@ expression: last_snapshot
|
||||
│ ││line18 │
|
||||
│ ││li█e19 │
|
||||
└──────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘
|
||||
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SCROLL <o> SESSION <q> QUIT
|
||||
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SEARCH <o> SESSION <q> QUIT
|
||||
Tip: Alt + <n> => new pane. Alt + <←↓↑→ or hjkl> => navigate. Alt + <+-> => resize pane.
|
||||
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
source: src/tests/e2e/cases.rs
|
||||
assertion_line: 151
|
||||
assertion_line: 154
|
||||
expression: last_snapshot
|
||||
---
|
||||
Zellij (e2e-test) Tab #1
|
||||
@ -25,5 +25,5 @@ expression: last_snapshot
|
||||
│ ││ │
|
||||
│ ││ │
|
||||
└──────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘
|
||||
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SCROLL <o> SESSION <q> QUIT
|
||||
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SEARCH <o> SESSION <q> QUIT
|
||||
Tip: Alt + <n> => new pane. Alt + <←↓↑→ or hjkl> => navigate. Alt + <+-> => resize pane.
|
||||
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
source: src/tests/e2e/cases.rs
|
||||
assertion_line: 1200
|
||||
assertion_line: 1163
|
||||
expression: last_snapshot
|
||||
---
|
||||
Zellij (e2e-test) Tab #1
|
||||
@ -25,5 +25,5 @@ $ │$ █
|
||||
│
|
||||
│
|
||||
│
|
||||
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SCROLL <o> SESSION <q> QUIT
|
||||
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SEARCH <o> SESSION <q> QUIT
|
||||
Tip: Alt + <n> => new pane. Alt + <←↓↑→ or hjkl> => navigate. Alt + <+-> => resize pane.
|
||||
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
source: src/tests/e2e/cases.rs
|
||||
assertion_line: 104
|
||||
assertion_line: 107
|
||||
expression: last_snapshot
|
||||
---
|
||||
Zellij (e2e-test) Tab #1
|
||||
@ -25,5 +25,5 @@ expression: last_snapshot
|
||||
│ │
|
||||
│ │
|
||||
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SCROLL <o> SESSION <q> QUIT
|
||||
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SEARCH <o> SESSION <q> QUIT
|
||||
Tip: Alt + <n> => new pane. Alt + <←↓↑→ or hjkl> => navigate. Alt + <+-> => resize pane.
|
||||
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
source: src/tests/e2e/cases.rs
|
||||
assertion_line: 1804
|
||||
assertion_line: 1767
|
||||
expression: last_snapshot
|
||||
---
|
||||
Zellij (e2e-test) Tab #1
|
||||
@ -25,5 +25,5 @@ expression: last_snapshot
|
||||
│ ││ │
|
||||
│ ││ │
|
||||
└──────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘
|
||||
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SCROLL <o> SESSION <q> QUIT
|
||||
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SEARCH <o> SESSION <q> QUIT
|
||||
Tip: Alt + <n> => new pane. Alt + <←↓↑→ or hjkl> => navigate. Alt + <+-> => resize pane.
|
||||
|
@ -1,7 +1,7 @@
|
||||
---
|
||||
source: src/tests/e2e/cases.rs
|
||||
assertion_line: 1683
|
||||
expression: last_snapshot
|
||||
|
||||
---
|
||||
Zellij (e2e-test) Tab #1
|
||||
┌ Pane #1 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||||
@ -25,5 +25,5 @@ expression: last_snapshot
|
||||
│ │
|
||||
│ │
|
||||
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SCROLL <o> SESSION <q> QUIT
|
||||
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SEARCH <o> SESSION <q> QUIT
|
||||
(FLOATING PANES VISIBLE): Press Ctrl-p + <w> to hide.
|
||||
|
@ -1,7 +1,7 @@
|
||||
---
|
||||
source: src/tests/e2e/cases.rs
|
||||
assertion_line: 334
|
||||
expression: last_snapshot
|
||||
|
||||
---
|
||||
Zellij (e2e-test) Tab #1
|
||||
┌ Pane #2 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||||
@ -25,5 +25,5 @@ expression: last_snapshot
|
||||
│ │
|
||||
│ │
|
||||
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SCROLL <o> SESSION <q> QUIT
|
||||
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SEARCH <o> SESSION <q> QUIT
|
||||
(FULLSCREEN): + 1 hidden panes
|
||||
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
source: src/tests/e2e/cases.rs
|
||||
assertion_line: 702
|
||||
assertion_line: 682
|
||||
expression: last_snapshot
|
||||
---
|
||||
Zellij (e2e-test) Tab #1
|
||||
@ -25,5 +25,5 @@ expression: last_snapshot
|
||||
│ │
|
||||
│ │
|
||||
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SCROLL <o> SESSION <q> QUIT
|
||||
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SEARCH <o> SESSION <q> QUIT
|
||||
Tip: Alt + <n> => new pane. Alt + <←↓↑→ or hjkl> => navigate. Alt + <+-> => resize pane.
|
||||
|
@ -1,5 +1,6 @@
|
||||
---
|
||||
source: src/tests/e2e/cases.rs
|
||||
assertion_line: 1914
|
||||
expression: last_snapshot
|
||||
---
|
||||
Zellij (e2e-test) Tab #1
|
||||
@ -24,5 +25,5 @@ expression: last_snapshot
|
||||
│ │
|
||||
│ │
|
||||
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SCROLL <o> SESSION <q> QUIT
|
||||
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SEARCH <o> SESSION <q> QUIT
|
||||
Tip: Alt + <n> => new pane. Alt + <←↓↑→ or hjkl> => navigate. Alt + <+-> => resize pane.
|
||||
|
@ -1,5 +1,6 @@
|
||||
---
|
||||
source: src/tests/e2e/cases.rs
|
||||
assertion_line: 1865
|
||||
expression: last_snapshot
|
||||
---
|
||||
Zellij (e2e-test) Tab #1
|
||||
@ -24,5 +25,5 @@ expression: last_snapshot
|
||||
│ │
|
||||
│ │
|
||||
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SCROLL <o> SESSION <q> QUIT
|
||||
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SEARCH <o> SESSION <q> QUIT
|
||||
Tip: Alt + <n> => new pane. Alt + <←↓↑→ or hjkl> => navigate. Alt + <+-> => resize pane.
|
||||
|
@ -30,18 +30,22 @@ fn vte_goto_instruction(x_coords: usize, y_coords: usize, vte_output: &mut Strin
|
||||
}
|
||||
|
||||
fn adjust_styles_for_possible_selection(
|
||||
chunk_selection_and_background_color: Option<(Selection, AnsiCode)>,
|
||||
chunk_selection_and_colors: Vec<(Selection, AnsiCode, Option<AnsiCode>)>,
|
||||
character_styles: CharacterStyles,
|
||||
chunk_y: usize,
|
||||
chunk_width: usize,
|
||||
) -> CharacterStyles {
|
||||
chunk_selection_and_background_color
|
||||
.and_then(|(selection, background_color)| {
|
||||
if selection.contains(chunk_y, chunk_width) {
|
||||
Some(character_styles.background(Some(background_color)))
|
||||
} else {
|
||||
None
|
||||
chunk_selection_and_colors
|
||||
.iter()
|
||||
.find(|(selection, _background_color, _foreground_color)| {
|
||||
selection.contains(chunk_y, chunk_width)
|
||||
})
|
||||
.map(|(_selection, background_color, foreground_color)| {
|
||||
let mut character_styles = character_styles.background(Some(*background_color));
|
||||
if let Some(foreground_color) = foreground_color {
|
||||
character_styles = character_styles.foreground(Some(*foreground_color));
|
||||
}
|
||||
character_styles
|
||||
})
|
||||
.unwrap_or(character_styles)
|
||||
}
|
||||
@ -76,14 +80,13 @@ fn serialize_chunks(
|
||||
let mut sixel_vte: Option<String> = None;
|
||||
let link_handler = link_handler.map(|l_h| l_h.borrow());
|
||||
for character_chunk in character_chunks {
|
||||
let chunk_selection_and_background_color = character_chunk.selection_and_background_color();
|
||||
let chunk_changed_colors = character_chunk.changed_colors();
|
||||
let mut character_styles = CharacterStyles::new();
|
||||
vte_goto_instruction(character_chunk.x, character_chunk.y, &mut vte_output);
|
||||
let mut chunk_width = character_chunk.x;
|
||||
for t_character in character_chunk.terminal_characters.iter() {
|
||||
let current_character_styles = adjust_styles_for_possible_selection(
|
||||
chunk_selection_and_background_color,
|
||||
character_chunk.selection_and_colors(),
|
||||
t_character.styles,
|
||||
character_chunk.y,
|
||||
chunk_width,
|
||||
@ -642,7 +645,7 @@ pub struct CharacterChunk {
|
||||
pub x: usize,
|
||||
pub y: usize,
|
||||
pub changed_colors: Option<[Option<AnsiCode>; 256]>,
|
||||
selection_and_background_color: Option<(Selection, AnsiCode)>,
|
||||
selection_and_colors: Vec<(Selection, AnsiCode, Option<AnsiCode>)>, // Selection, background color, optional foreground color
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
@ -665,18 +668,23 @@ impl CharacterChunk {
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
pub fn add_selection_and_background(
|
||||
pub fn add_selection_and_colors(
|
||||
&mut self,
|
||||
selection: Selection,
|
||||
background_color: AnsiCode,
|
||||
foreground_color: Option<AnsiCode>,
|
||||
offset_x: usize,
|
||||
offset_y: usize,
|
||||
) {
|
||||
self.selection_and_background_color =
|
||||
Some((selection.offset(offset_x, offset_y), background_color));
|
||||
self.selection_and_colors.push((
|
||||
selection.offset(offset_x, offset_y),
|
||||
background_color,
|
||||
foreground_color,
|
||||
));
|
||||
}
|
||||
pub fn selection_and_background_color(&self) -> Option<(Selection, AnsiCode)> {
|
||||
self.selection_and_background_color
|
||||
pub fn selection_and_colors(&self) -> Vec<(Selection, AnsiCode, Option<AnsiCode>)> {
|
||||
// Selection, background color, optional foreground color
|
||||
self.selection_and_colors.clone()
|
||||
}
|
||||
pub fn add_changed_colors(&mut self, changed_colors: Option<[Option<AnsiCode>; 256]>) {
|
||||
self.changed_colors = changed_colors;
|
||||
@ -776,6 +784,15 @@ impl OutputBuffer {
|
||||
self.changed_lines.push(line_index);
|
||||
}
|
||||
}
|
||||
pub fn update_lines(&mut self, start: usize, end: usize) {
|
||||
if !self.should_update_all_lines {
|
||||
for idx in start..=end {
|
||||
if !self.changed_lines.contains(&idx) {
|
||||
self.changed_lines.push(idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn update_all_lines(&mut self) {
|
||||
self.clear();
|
||||
self.should_update_all_lines = true;
|
||||
|
@ -1,4 +1,5 @@
|
||||
use super::sixel::{PixelRect, SixelGrid, SixelImageStore};
|
||||
use std::borrow::Cow;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::rc::Rc;
|
||||
@ -29,6 +30,7 @@ use zellij_utils::{consts::VERSION, shared::version_number};
|
||||
use crate::output::{CharacterChunk, OutputBuffer, SixelImageChunk};
|
||||
use crate::panes::alacritty_functions::{parse_number, xparse_color};
|
||||
use crate::panes::link_handler::LinkHandler;
|
||||
use crate::panes::search::SearchResult;
|
||||
use crate::panes::selection::Selection;
|
||||
use crate::panes::terminal_character::{
|
||||
AnsiCode, CharacterStyles, CharsetIndex, Cursor, CursorShape, StandardCharset,
|
||||
@ -299,9 +301,9 @@ macro_rules! dump_screen {
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Grid {
|
||||
lines_above: VecDeque<Row>,
|
||||
viewport: Vec<Row>,
|
||||
lines_below: Vec<Row>,
|
||||
pub(crate) lines_above: VecDeque<Row>,
|
||||
pub(crate) viewport: Vec<Row>,
|
||||
pub(crate) lines_below: Vec<Row>,
|
||||
horizontal_tabstops: BTreeSet<usize>,
|
||||
alternate_screen_state: Option<AlternateScreenState>,
|
||||
cursor: Cursor,
|
||||
@ -316,7 +318,7 @@ pub struct Grid {
|
||||
preceding_char: Option<TerminalCharacter>,
|
||||
terminal_emulator_colors: Rc<RefCell<Palette>>,
|
||||
terminal_emulator_color_codes: Rc<RefCell<HashMap<usize, String>>>,
|
||||
output_buffer: OutputBuffer,
|
||||
pub(crate) output_buffer: OutputBuffer,
|
||||
title_stack: Vec<String>,
|
||||
character_cell_size: Rc<RefCell<Option<SizeInPixels>>>,
|
||||
sixel_grid: SixelGrid,
|
||||
@ -339,6 +341,7 @@ pub struct Grid {
|
||||
pub ring_bell: bool,
|
||||
scrollback_buffer_lines: usize,
|
||||
pub mouse_mode: bool,
|
||||
pub search_results: SearchResult,
|
||||
}
|
||||
|
||||
impl Debug for Grid {
|
||||
@ -378,10 +381,13 @@ impl Debug for Grid {
|
||||
|
||||
// display terminal characters with stripped styles
|
||||
for (i, row) in buffer.iter().enumerate() {
|
||||
let mut cow_row = Cow::Borrowed(row);
|
||||
self.search_results
|
||||
.mark_search_results_in_row(&mut cow_row, i);
|
||||
if row.is_canonical {
|
||||
writeln!(f, "{:02?} (C): {:?}", i, row)?;
|
||||
writeln!(f, "{:02?} (C): {:?}", i, cow_row)?;
|
||||
} else {
|
||||
writeln!(f, "{:02?} (W): {:?}", i, row)?;
|
||||
writeln!(f, "{:02?} (W): {:?}", i, cow_row)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
@ -439,6 +445,7 @@ impl Grid {
|
||||
scrollback_buffer_lines: 0,
|
||||
mouse_mode: false,
|
||||
character_cell_size,
|
||||
search_results: Default::default(),
|
||||
sixel_grid,
|
||||
}
|
||||
}
|
||||
@ -575,7 +582,9 @@ impl Grid {
|
||||
}
|
||||
y_coordinates
|
||||
}
|
||||
pub fn scroll_up_one_line(&mut self) {
|
||||
|
||||
pub fn scroll_up_one_line(&mut self) -> bool {
|
||||
let mut found_something = false;
|
||||
if !self.lines_above.is_empty() && self.viewport.len() == self.height {
|
||||
self.is_scrolled = true;
|
||||
let line_to_push_down = self.viewport.pop().unwrap();
|
||||
@ -593,10 +602,16 @@ impl Grid {
|
||||
.saturating_sub(transferred_rows_height);
|
||||
|
||||
self.selection.move_down(1);
|
||||
// Move all search-selections down one line as well
|
||||
found_something = self
|
||||
.search_results
|
||||
.move_down(1, &self.viewport, self.height);
|
||||
}
|
||||
self.output_buffer.update_all_lines();
|
||||
found_something
|
||||
}
|
||||
pub fn scroll_down_one_line(&mut self) {
|
||||
pub fn scroll_down_one_line(&mut self) -> bool {
|
||||
let mut found_something = false;
|
||||
if !self.lines_below.is_empty() && self.viewport.len() == self.height {
|
||||
let mut line_to_push_up = self.viewport.remove(0);
|
||||
|
||||
@ -629,11 +644,16 @@ impl Grid {
|
||||
);
|
||||
|
||||
self.selection.move_up(1);
|
||||
// Move all search-selections up one line as well
|
||||
found_something =
|
||||
self.search_results
|
||||
.move_up(1, &self.viewport, &self.lines_below, self.height);
|
||||
self.output_buffer.update_all_lines();
|
||||
}
|
||||
if self.lines_below.is_empty() {
|
||||
self.is_scrolled = false;
|
||||
}
|
||||
found_something
|
||||
}
|
||||
fn force_change_size(&mut self, new_rows: usize, new_columns: usize) {
|
||||
// this is an ugly hack - it's here because sometimes we need to change_size to the
|
||||
@ -844,6 +864,10 @@ impl Grid {
|
||||
self.set_scroll_region_to_viewport_size();
|
||||
}
|
||||
self.scrollback_buffer_lines = self.recalculate_scrollback_buffer_count();
|
||||
self.search_results.selections.clear();
|
||||
self.search_viewport();
|
||||
// If we have thrown out the active element, set it to None
|
||||
self.search_results.unset_active_selection_if_nonexistent();
|
||||
self.output_buffer.update_all_lines();
|
||||
}
|
||||
pub fn as_character_lines(&self) -> Vec<Vec<TerminalCharacter>> {
|
||||
@ -1443,6 +1467,7 @@ impl Grid {
|
||||
self.output_buffer.update_all_lines();
|
||||
self.changed_colors = None;
|
||||
self.scrollback_buffer_lines = 0;
|
||||
self.search_results = Default::default();
|
||||
self.sixel_scrolling = false;
|
||||
if let Some(images_to_reap) = self.sixel_grid.clear() {
|
||||
self.sixel_grid.reap_images(images_to_reap);
|
||||
|
@ -3,6 +3,7 @@ mod floating_panes;
|
||||
pub mod grid;
|
||||
pub mod link_handler;
|
||||
mod plugin_pane;
|
||||
mod search;
|
||||
pub mod selection;
|
||||
pub mod sixel;
|
||||
pub mod terminal_character;
|
||||
|
663
zellij-server/src/panes/search.rs
Normal file
663
zellij-server/src/panes/search.rs
Normal file
@ -0,0 +1,663 @@
|
||||
use crate::panes::selection::Selection;
|
||||
use crate::panes::terminal_character::TerminalCharacter;
|
||||
use crate::panes::{Grid, Row};
|
||||
use std::borrow::Cow;
|
||||
use std::fmt::Debug;
|
||||
use zellij_utils::input::actions::SearchDirection;
|
||||
use zellij_utils::position::Position;
|
||||
|
||||
// If char is neither alphanumeric nor an underscore do we consider it a word-boundary
|
||||
fn is_word_boundary(x: &Option<char>) -> bool {
|
||||
x.map_or(true, |c| !c.is_ascii_alphanumeric() && c != '_')
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum SearchSource<'a> {
|
||||
Main(&'a Row),
|
||||
Tail(&'a Row),
|
||||
}
|
||||
|
||||
impl<'a> SearchSource<'a> {
|
||||
/// Returns true, if a new source was found, false otherwise (reached the end of the tail).
|
||||
/// If we are in the middle of a line, nothing will be changed.
|
||||
/// Only, when we have to switch to a new line, will the source update itself,
|
||||
/// as well as the corresponding indices.
|
||||
fn get_next_source(
|
||||
&mut self,
|
||||
ridx: &mut usize,
|
||||
hidx: &mut usize,
|
||||
tailit: &mut std::slice::Iter<&'a Row>,
|
||||
start: &Option<Position>,
|
||||
) -> bool {
|
||||
match self {
|
||||
SearchSource::Main(row) => {
|
||||
// If we are at the end of the main row, we need to start looking into the tail
|
||||
if hidx >= &mut row.columns.len() {
|
||||
let curr_tail = tailit.next();
|
||||
// If we are at the end and found a partial hit, we have to extend the search into the next line
|
||||
if let Some(curr_tail) = start.and(curr_tail) {
|
||||
*ridx += 1; // Go one line down
|
||||
*hidx = 0; // and start from the beginning of the new line
|
||||
*self = SearchSource::Tail(curr_tail);
|
||||
} else {
|
||||
return false; // We reached the end of the tail
|
||||
}
|
||||
}
|
||||
},
|
||||
SearchSource::Tail(tail) => {
|
||||
if hidx >= &mut tail.columns.len() {
|
||||
// If we are still searching (didn't hit a mismatch yet) and there is still more tail to go
|
||||
// just continue with the next line
|
||||
if let Some(curr_tail) = tailit.next() {
|
||||
*ridx += 1; // Go one line down
|
||||
*hidx = 0; // and start from the beginning of the new line
|
||||
*self = SearchSource::Tail(curr_tail);
|
||||
} else {
|
||||
return false; // We reached the end of the tail
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
// We have found a new source, or we are in the middle of a line, so no need to change anything
|
||||
true
|
||||
}
|
||||
|
||||
// Get the char at hidx and, if existing, the following char as well
|
||||
fn get_next_two_chars(&self, hidx: usize, whole_word_search: bool) -> (char, Option<char>) {
|
||||
// Get the current haystack character
|
||||
let haystack_char = match self {
|
||||
SearchSource::Main(row) => row.columns[hidx].character,
|
||||
SearchSource::Tail(tail) => tail.columns[hidx].character,
|
||||
};
|
||||
|
||||
// Get the next haystack character (relevant for whole-word search only)
|
||||
let next_haystack_char = if whole_word_search {
|
||||
// Everything (incl. end of line) that is not [a-zA-Z0-9_] is considered a word boundary
|
||||
match self {
|
||||
SearchSource::Main(row) => row.columns.get(hidx + 1).map(|c| c.character),
|
||||
SearchSource::Tail(tail) => tail.columns.get(hidx + 1).map(|c| c.character),
|
||||
}
|
||||
} else {
|
||||
None // Doesn't get used, when not doing whole-word search
|
||||
};
|
||||
(haystack_char, next_haystack_char)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct SearchResult {
|
||||
// What we have already found in the viewport
|
||||
pub selections: Vec<Selection>,
|
||||
// Which of the selections we found is currently 'active' (highlighted differently)
|
||||
pub active: Option<Selection>,
|
||||
// What we are looking for
|
||||
pub needle: String,
|
||||
// Does case matter?
|
||||
pub case_insensitive: bool,
|
||||
// Only search whole words, not parts inside a word
|
||||
pub whole_word_only: bool, // TODO
|
||||
// Jump from the bottom to the top (or vice versa), if we run out of lines to search
|
||||
pub wrap_search: bool,
|
||||
}
|
||||
|
||||
impl SearchResult {
|
||||
/// This is only used for Debug formatting Grid, which itself is only used
|
||||
/// for tests.
|
||||
#[allow(clippy::ptr_arg)]
|
||||
pub(crate) fn mark_search_results_in_row(&self, row: &mut Cow<Row>, ridx: usize) {
|
||||
for s in &self.selections {
|
||||
if s.contains_row(ridx) {
|
||||
let replacement_char = if Some(s) == self.active.as_ref() {
|
||||
'_'
|
||||
} else {
|
||||
'#'
|
||||
};
|
||||
|
||||
let (skip, take) = if ridx as isize == s.start.line() {
|
||||
let skip = s.start.column();
|
||||
let take = if s.end.line() == s.start.line() {
|
||||
s.end.column() - s.start.column()
|
||||
} else {
|
||||
// Just mark the rest of the line. This number is certainly too big but the iterator takes care of this
|
||||
row.columns.len()
|
||||
};
|
||||
(skip, take)
|
||||
} else if ridx as isize == s.end.line() {
|
||||
// We wrapped a line and the end is in this row, so take from the begging to the end
|
||||
(0, s.end.column())
|
||||
} else {
|
||||
// We are in the middle (start is above and end is below), so mark all
|
||||
(0, row.columns.len())
|
||||
};
|
||||
|
||||
row.to_mut()
|
||||
.columns
|
||||
.iter_mut()
|
||||
.skip(skip)
|
||||
.take(take)
|
||||
.for_each(|x| *x = TerminalCharacter::new(replacement_char));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn has_modifiers_set(&self) -> bool {
|
||||
self.wrap_search || self.whole_word_only || self.case_insensitive
|
||||
}
|
||||
|
||||
fn check_if_haystack_char_matches_needle(
|
||||
&self,
|
||||
nidx: usize,
|
||||
needle_char: char,
|
||||
haystack_char: char,
|
||||
prev_haystack_char: Option<char>,
|
||||
) -> bool {
|
||||
let mut chars_match = if self.case_insensitive {
|
||||
// Case insensitive search
|
||||
// Currently only ascii, as this whole search-function is very sub-optimal anyways
|
||||
haystack_char.to_ascii_lowercase() == needle_char.to_ascii_lowercase()
|
||||
} else {
|
||||
// Case sensitive search
|
||||
haystack_char == needle_char
|
||||
};
|
||||
|
||||
// Whole-word search
|
||||
// It's a match only, if the first haystack char that is _not_ a hit, is a word-boundary
|
||||
if chars_match
|
||||
&& self.whole_word_only
|
||||
&& nidx == 0
|
||||
&& !is_word_boundary(&prev_haystack_char)
|
||||
{
|
||||
// Start of the match is not a word boundary, so this is not a hit
|
||||
chars_match = false;
|
||||
}
|
||||
|
||||
chars_match
|
||||
}
|
||||
|
||||
/// Search a row and its tail.
|
||||
/// The tail are all the non-canonical lines below `row`, with `row` not necessarily being canonical itself.
|
||||
pub(crate) fn search_row(&self, mut ridx: usize, row: &Row, tail: &[&Row]) -> Vec<Selection> {
|
||||
let mut res = Vec::new();
|
||||
if self.needle.is_empty() || row.columns.is_empty() {
|
||||
return res;
|
||||
}
|
||||
|
||||
let mut tailit = tail.iter();
|
||||
let mut source = SearchSource::Main(row); // Where we currently get the haystack-characters from
|
||||
let orig_ridx = ridx;
|
||||
let mut start = None; // If we find a hit, this is where it starts
|
||||
let mut nidx = 0; // Needle index
|
||||
let mut hidx = 0; // Haystack index
|
||||
let mut prev_haystack_char: Option<char> = None;
|
||||
loop {
|
||||
// Get the current and next haystack character
|
||||
let (mut haystack_char, next_haystack_char) =
|
||||
source.get_next_two_chars(hidx, self.whole_word_only);
|
||||
|
||||
// Get current needle character
|
||||
let needle_char = self.needle.chars().nth(nidx).unwrap(); // Unwrapping is safe here
|
||||
|
||||
// Check if needle and haystack match (with search-options)
|
||||
let chars_match = self.check_if_haystack_char_matches_needle(
|
||||
nidx,
|
||||
needle_char,
|
||||
haystack_char,
|
||||
prev_haystack_char,
|
||||
);
|
||||
|
||||
if chars_match {
|
||||
// If the needle is only 1 long, the next `if` could also happen, so we are not merging it into one big if-else
|
||||
if nidx == 0 {
|
||||
start = Some(Position::new(ridx as i32, hidx as u16));
|
||||
}
|
||||
if nidx == self.needle.len() - 1 {
|
||||
let mut end_found = true;
|
||||
// If we search whole-word-only, the next non-needle char needs to be a word-boundary,
|
||||
// otherwise its not a hit (e.g. some occurrence inside a longer word).
|
||||
if self.whole_word_only && !is_word_boundary(&next_haystack_char) {
|
||||
// The end of the match is not a word boundary, so this is not a hit!
|
||||
// We have to jump back from where we started (plus one char)
|
||||
nidx = 0;
|
||||
ridx = start.unwrap().line() as usize;
|
||||
hidx = start.unwrap().column(); // Will be incremented below
|
||||
if start.unwrap().line() as usize == orig_ridx {
|
||||
source = SearchSource::Main(row);
|
||||
haystack_char = row.columns[hidx].character; // so that prev_char gets set correctly
|
||||
} else {
|
||||
// The -1 comes from the main row
|
||||
let tail_idx = start.unwrap().line() as usize - orig_ridx - 1;
|
||||
// We have to reset the tail-iterator as well.
|
||||
tailit = tail[tail_idx..].iter();
|
||||
let trow = tailit.next().unwrap();
|
||||
haystack_char = trow.columns[hidx].character; // so that prev_char gets set correctly
|
||||
source = SearchSource::Tail(trow);
|
||||
}
|
||||
start = None;
|
||||
end_found = false;
|
||||
}
|
||||
if end_found {
|
||||
let mut selection = Selection::default();
|
||||
selection.start(start.unwrap());
|
||||
selection.end(Position::new(ridx as i32, (hidx + 1) as u16));
|
||||
res.push(selection);
|
||||
nidx = 0;
|
||||
if matches!(source, SearchSource::Tail(..)) {
|
||||
// When searching the tail, we can only find one additional selection, so stopping here
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
nidx += 1;
|
||||
}
|
||||
} else {
|
||||
// Chars don't match. Start searching the needle from the beginning
|
||||
start = None;
|
||||
nidx = 0;
|
||||
if matches!(source, SearchSource::Tail(..)) {
|
||||
// When searching the tail and we find a mismatch, just quit right now
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
hidx += 1;
|
||||
prev_haystack_char = Some(haystack_char);
|
||||
// We might need to switch to a new line in the tail
|
||||
if !source.get_next_source(&mut ridx, &mut hidx, &mut tailit, &start) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// The tail may have not been wrapped yet (when coming from lines_below),
|
||||
// so it could be that the end extends across more characters than the row is wide.
|
||||
// Therefore we need to reflow the end:
|
||||
for s in res.iter_mut() {
|
||||
while s.end.column() > row.width() {
|
||||
s.end.column.0 -= row.width();
|
||||
s.end.line.0 += 1;
|
||||
}
|
||||
}
|
||||
res
|
||||
}
|
||||
|
||||
pub(crate) fn move_active_selection_to_next(&mut self) {
|
||||
if let Some(active_idx) = self.active {
|
||||
self.active = self
|
||||
.selections
|
||||
.iter()
|
||||
.skip_while(|s| *s != &active_idx)
|
||||
.nth(1)
|
||||
.cloned();
|
||||
} else {
|
||||
self.active = self.selections.first().cloned();
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn move_active_selection_to_prev(&mut self) {
|
||||
if let Some(active_idx) = self.active {
|
||||
self.active = self
|
||||
.selections
|
||||
.iter()
|
||||
.rev()
|
||||
.skip_while(|s| *s != &active_idx)
|
||||
.nth(1)
|
||||
.cloned();
|
||||
} else {
|
||||
self.active = self.selections.last().cloned();
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn unset_active_selection_if_nonexistent(&mut self) {
|
||||
if let Some(active_idx) = self.active {
|
||||
if !self.selections.contains(&active_idx) {
|
||||
self.active = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn move_down(
|
||||
&mut self,
|
||||
amount: usize,
|
||||
viewport: &[Row],
|
||||
grid_height: usize,
|
||||
) -> bool {
|
||||
let mut found_something = false;
|
||||
self.selections
|
||||
.iter_mut()
|
||||
.chain(self.active.iter_mut())
|
||||
.for_each(|x| x.move_down(amount));
|
||||
|
||||
// Throw out all search-results outside of the new viewport
|
||||
self.adjust_selections_to_moved_viewport(grid_height);
|
||||
|
||||
// Search the new line for our needle
|
||||
if !self.needle.is_empty() {
|
||||
if let Some(row) = viewport.first() {
|
||||
let mut tail = Vec::new();
|
||||
loop {
|
||||
let tail_idx = 1 + tail.len();
|
||||
if tail_idx < viewport.len() && !viewport[tail_idx].is_canonical {
|
||||
tail.push(&viewport[tail_idx]);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
let selections = self.search_row(0, row, &tail);
|
||||
for selection in selections.iter().rev() {
|
||||
self.selections.insert(0, *selection);
|
||||
found_something = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
found_something
|
||||
}
|
||||
|
||||
pub(crate) fn move_up(
|
||||
&mut self,
|
||||
amount: usize,
|
||||
viewport: &[Row],
|
||||
lines_below: &[Row],
|
||||
grid_height: usize,
|
||||
) -> bool {
|
||||
let mut found_something = false;
|
||||
self.selections
|
||||
.iter_mut()
|
||||
.chain(self.active.iter_mut())
|
||||
.for_each(|x| x.move_up(amount));
|
||||
// Throw out all search-results outside of the new viewport
|
||||
self.adjust_selections_to_moved_viewport(grid_height);
|
||||
|
||||
// Search the new line for our needle
|
||||
if !self.needle.is_empty() {
|
||||
if let Some(row) = viewport.last() {
|
||||
let tail: Vec<&Row> = lines_below.iter().take_while(|r| !r.is_canonical).collect();
|
||||
let selections = self.search_row(viewport.len() - 1, row, &tail);
|
||||
for selection in selections {
|
||||
// We are only interested in results that start in the this new row
|
||||
if selection.start.line() as usize == viewport.len() - 1 {
|
||||
self.selections.push(selection);
|
||||
found_something = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
found_something
|
||||
}
|
||||
|
||||
fn adjust_selections_to_moved_viewport(&mut self, grid_height: usize) {
|
||||
// Throw out all search-results outside of the new viewport
|
||||
self.selections
|
||||
.retain(|s| (s.start.line() as usize) < grid_height && s.end.line() >= 0);
|
||||
// If we have thrown out the active element, set it to None
|
||||
self.unset_active_selection_if_nonexistent();
|
||||
}
|
||||
}
|
||||
|
||||
impl Grid {
|
||||
pub fn search_down(&mut self) {
|
||||
self.search_scrollbuffer(SearchDirection::Down);
|
||||
}
|
||||
|
||||
pub fn search_up(&mut self) {
|
||||
self.search_scrollbuffer(SearchDirection::Up);
|
||||
}
|
||||
|
||||
pub fn clear_search(&mut self) {
|
||||
// Clearing all previous highlights
|
||||
for res in &self.search_results.selections {
|
||||
self.output_buffer
|
||||
.update_lines(res.start.line() as usize, res.end.line() as usize);
|
||||
}
|
||||
self.search_results = Default::default();
|
||||
}
|
||||
|
||||
pub fn set_search_string(&mut self, needle: &str) {
|
||||
self.search_results.needle = needle.to_string();
|
||||
self.search_viewport();
|
||||
// If the current viewport does not contain any hits,
|
||||
// we jump around until we find something. Starting
|
||||
// going backwards.
|
||||
if self.search_results.selections.is_empty() {
|
||||
self.search_up();
|
||||
}
|
||||
if self.search_results.selections.is_empty() {
|
||||
self.search_down();
|
||||
}
|
||||
// We still don't want to pre-select anything at this stage
|
||||
self.search_results.active = None;
|
||||
self.is_scrolled = true;
|
||||
}
|
||||
|
||||
pub fn search_viewport(&mut self) {
|
||||
for ridx in 0..self.viewport.len() {
|
||||
let row = &self.viewport[ridx];
|
||||
let mut tail = Vec::new();
|
||||
loop {
|
||||
let tail_idx = ridx + tail.len() + 1;
|
||||
if tail_idx < self.viewport.len() && !self.viewport[tail_idx].is_canonical {
|
||||
tail.push(&self.viewport[tail_idx]);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
let selections = self.search_results.search_row(ridx, row, &tail);
|
||||
for sel in &selections {
|
||||
// Cast works because we can' be negative here
|
||||
self.output_buffer
|
||||
.update_lines(sel.start.line() as usize, sel.end.line() as usize);
|
||||
}
|
||||
|
||||
for selection in selections {
|
||||
self.search_results.selections.push(selection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn toggle_search_case_sensitivity(&mut self) {
|
||||
self.search_results.case_insensitive = !self.search_results.case_insensitive;
|
||||
for line in self.search_results.selections.drain(..) {
|
||||
self.output_buffer
|
||||
.update_lines(line.start.line() as usize, line.end.line() as usize);
|
||||
}
|
||||
self.search_viewport();
|
||||
// Maybe the selection we had is now gone
|
||||
self.search_results.unset_active_selection_if_nonexistent();
|
||||
}
|
||||
|
||||
pub fn toggle_search_wrap(&mut self) {
|
||||
self.search_results.wrap_search = !self.search_results.wrap_search;
|
||||
}
|
||||
|
||||
pub fn toggle_search_whole_words(&mut self) {
|
||||
self.search_results.whole_word_only = !self.search_results.whole_word_only;
|
||||
for line in self.search_results.selections.drain(..) {
|
||||
self.output_buffer
|
||||
.update_lines(line.start.line() as usize, line.end.line() as usize);
|
||||
}
|
||||
self.search_results.active = None;
|
||||
self.search_viewport();
|
||||
// Maybe the selection we had is now gone
|
||||
self.search_results.unset_active_selection_if_nonexistent();
|
||||
}
|
||||
|
||||
fn search_scrollbuffer(&mut self, dir: SearchDirection) {
|
||||
let first_sel = self.search_results.selections.first();
|
||||
let last_sel = self.search_results.selections.last();
|
||||
|
||||
let search_viewport_for_the_first_time =
|
||||
self.search_results.active.is_none() && !self.search_results.selections.is_empty();
|
||||
|
||||
// We are not at the end yet, so we can iterate to the next search-result within the current viewport
|
||||
let search_viewport_again = !self.search_results.selections.is_empty()
|
||||
&& self.search_results.active.is_some()
|
||||
&& match dir {
|
||||
SearchDirection::Up => self.search_results.active.as_ref() != first_sel,
|
||||
SearchDirection::Down => self.search_results.active.as_ref() != last_sel,
|
||||
};
|
||||
|
||||
if search_viewport_for_the_first_time || search_viewport_again {
|
||||
// We can stay in the viewport and just move the active selection
|
||||
self.search_viewport_again(search_viewport_for_the_first_time, dir);
|
||||
} else {
|
||||
// Need to move the viewport
|
||||
let found_something = self.search_viewport_move(dir);
|
||||
|
||||
// We haven't found anything, but we are allowed to wrap around
|
||||
if !found_something && self.search_results.wrap_search {
|
||||
self.search_viewport_wrap(dir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn search_viewport_again(
|
||||
&mut self,
|
||||
search_viewport_for_the_first_time: bool,
|
||||
dir: SearchDirection,
|
||||
) {
|
||||
let new_active = match dir {
|
||||
SearchDirection::Up => self.search_results.selections.last().cloned().unwrap(),
|
||||
SearchDirection::Down => self.search_results.selections.first().cloned().unwrap(),
|
||||
};
|
||||
// We can stay in the viewport and just move the active selection
|
||||
let active_idx = self.search_results.active.get_or_insert(new_active);
|
||||
self.output_buffer.update_lines(
|
||||
active_idx.start.line() as usize,
|
||||
active_idx.end.line() as usize,
|
||||
);
|
||||
if !search_viewport_for_the_first_time {
|
||||
match dir {
|
||||
SearchDirection::Up => self.search_results.move_active_selection_to_prev(),
|
||||
SearchDirection::Down => self.search_results.move_active_selection_to_next(),
|
||||
};
|
||||
if let Some(new_active) = self.search_results.active {
|
||||
self.output_buffer.update_lines(
|
||||
new_active.start.line() as usize,
|
||||
new_active.end.line() as usize,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn search_reached_opposite_end(&mut self, dir: SearchDirection) -> bool {
|
||||
match dir {
|
||||
SearchDirection::Up => self.lines_above.is_empty(),
|
||||
SearchDirection::Down => self.lines_below.is_empty(),
|
||||
}
|
||||
}
|
||||
|
||||
fn search_viewport_move(&mut self, dir: SearchDirection) -> bool {
|
||||
// We need to move the viewport
|
||||
let mut rows = 0;
|
||||
let mut found_something = false;
|
||||
|
||||
// We might loose the current selection, if we can't find anything
|
||||
let current_active_selection = self.search_results.active;
|
||||
while !found_something && !self.search_reached_opposite_end(dir) {
|
||||
rows += 1;
|
||||
found_something = match dir {
|
||||
SearchDirection::Up => self.scroll_up_one_line(),
|
||||
SearchDirection::Down => self.scroll_down_one_line(),
|
||||
};
|
||||
}
|
||||
|
||||
if found_something {
|
||||
self.search_adjust_to_new_selection(dir);
|
||||
} else {
|
||||
// We didn't find something, so we scroll back to the start
|
||||
for _ in 0..rows {
|
||||
match dir {
|
||||
SearchDirection::Up => self.scroll_down_one_line(),
|
||||
SearchDirection::Down => self.scroll_up_one_line(),
|
||||
};
|
||||
}
|
||||
self.search_results.active = current_active_selection;
|
||||
}
|
||||
found_something
|
||||
}
|
||||
|
||||
fn search_adjust_to_new_selection(&mut self, dir: SearchDirection) {
|
||||
match dir {
|
||||
SearchDirection::Up => {
|
||||
self.search_results.move_active_selection_to_prev();
|
||||
},
|
||||
SearchDirection::Down => {
|
||||
// We may need to scroll a bit further, because we are at the beginning of the
|
||||
// search result, but the end might be invisible
|
||||
if let Some(last) = self.search_results.selections.last() {
|
||||
let distance = (last.end.line() - last.start.line()) as usize;
|
||||
if distance < self.height {
|
||||
for _ in 0..distance {
|
||||
self.scroll_down_one_line();
|
||||
}
|
||||
}
|
||||
}
|
||||
self.search_results.move_active_selection_to_next();
|
||||
},
|
||||
}
|
||||
self.output_buffer.update_all_lines();
|
||||
}
|
||||
|
||||
fn search_viewport_wrap(&mut self, dir: SearchDirection) {
|
||||
// We might loose the current selection, if we can't find anything
|
||||
let current_active_selection = self.search_results.active;
|
||||
// UP
|
||||
// Go to the opposite end (bottom when searching up and top when searching down)
|
||||
let mut rows = self.move_viewport_to_opposite_end(dir);
|
||||
|
||||
// We are at the bottom or top. Maybe we found already something there
|
||||
// If not, scroll back again, until we find something
|
||||
let mut found_something = match dir {
|
||||
SearchDirection::Up => self.search_results.selections.last().is_some(),
|
||||
SearchDirection::Down => self.search_results.selections.first().is_some(),
|
||||
};
|
||||
|
||||
// We didn't find anything at the opposing end of the scrollbuffer, so we scroll back until we find something
|
||||
if !found_something {
|
||||
while rows >= 0 && !found_something {
|
||||
rows -= 1;
|
||||
found_something = match dir {
|
||||
SearchDirection::Up => self.scroll_up_one_line(),
|
||||
SearchDirection::Down => self.scroll_down_one_line(),
|
||||
};
|
||||
}
|
||||
}
|
||||
if found_something {
|
||||
self.search_results.active = match dir {
|
||||
SearchDirection::Up => self.search_results.selections.last().cloned(),
|
||||
SearchDirection::Down => {
|
||||
// We need to scroll until the found item is at the top
|
||||
if let Some(first) = self.search_results.selections.first() {
|
||||
for _ in 0..first.start.line() {
|
||||
self.scroll_down_one_line();
|
||||
}
|
||||
}
|
||||
self.search_results.selections.first().cloned()
|
||||
},
|
||||
};
|
||||
self.output_buffer.update_all_lines();
|
||||
} else {
|
||||
// We didn't find anything, so we reset the old active selection
|
||||
self.search_results.active = current_active_selection;
|
||||
}
|
||||
}
|
||||
|
||||
fn move_viewport_to_opposite_end(&mut self, dir: SearchDirection) -> isize {
|
||||
let mut rows = 0;
|
||||
match dir {
|
||||
SearchDirection::Up => {
|
||||
// Go to the bottom
|
||||
while !self.lines_below.is_empty() {
|
||||
rows += 1;
|
||||
self.scroll_down_one_line();
|
||||
}
|
||||
},
|
||||
SearchDirection::Down => {
|
||||
// Go to the top
|
||||
while !self.lines_above.is_empty() {
|
||||
rows += 1;
|
||||
self.scroll_up_one_line();
|
||||
}
|
||||
},
|
||||
}
|
||||
rows
|
||||
}
|
||||
}
|
@ -4,7 +4,7 @@ use zellij_utils::position::Position;
|
||||
|
||||
// The selection is empty when start == end
|
||||
// it includes the character at start, and everything before end.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct Selection {
|
||||
pub start: Position,
|
||||
pub end: Position,
|
||||
|
@ -54,6 +54,7 @@ pub struct TerminalPane {
|
||||
frame: HashMap<ClientId, PaneFrame>,
|
||||
borderless: bool,
|
||||
fake_cursor_locations: HashSet<(usize, usize)>, // (x, y) - these hold a record of previous fake cursors which we need to clear on render
|
||||
search_term: String,
|
||||
}
|
||||
|
||||
impl Pane for TerminalPane {
|
||||
@ -225,12 +226,39 @@ impl Pane for TerminalPane {
|
||||
PaletteColor::Rgb(rgb) => AnsiCode::RgbCode(rgb),
|
||||
PaletteColor::EightBit(col) => AnsiCode::ColorIndex(col),
|
||||
};
|
||||
character_chunk.add_selection_and_background(
|
||||
character_chunk.add_selection_and_colors(
|
||||
self.grid.selection,
|
||||
background_color,
|
||||
None,
|
||||
content_x,
|
||||
content_y,
|
||||
);
|
||||
} else if !self.grid.search_results.selections.is_empty() {
|
||||
for res in self.grid.search_results.selections.iter() {
|
||||
if res.contains_row(character_chunk.y.saturating_sub(content_y)) {
|
||||
let (select_background_palette, select_foreground_palette) =
|
||||
if Some(res) == self.grid.search_results.active.as_ref() {
|
||||
(self.style.colors.orange, self.style.colors.black)
|
||||
} else {
|
||||
(self.style.colors.green, self.style.colors.black)
|
||||
};
|
||||
let background_color = match select_background_palette {
|
||||
PaletteColor::Rgb(rgb) => AnsiCode::RgbCode(rgb),
|
||||
PaletteColor::EightBit(col) => AnsiCode::ColorIndex(col),
|
||||
};
|
||||
let foreground_color = match select_foreground_palette {
|
||||
PaletteColor::Rgb(rgb) => AnsiCode::RgbCode(rgb),
|
||||
PaletteColor::EightBit(col) => AnsiCode::ColorIndex(col),
|
||||
};
|
||||
character_chunk.add_selection_and_colors(
|
||||
*res,
|
||||
background_color,
|
||||
Some(foreground_color),
|
||||
content_x,
|
||||
content_y,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if self.grid.ring_bell {
|
||||
@ -256,6 +284,31 @@ impl Pane for TerminalPane {
|
||||
&& frame_params.is_main_client
|
||||
{
|
||||
String::from("Enter name...")
|
||||
} else if input_mode == InputMode::EnterSearch
|
||||
&& frame_params.is_main_client
|
||||
&& self.search_term.is_empty()
|
||||
{
|
||||
String::from("Enter search...")
|
||||
} else if (input_mode == InputMode::EnterSearch || input_mode == InputMode::Search)
|
||||
&& !self.search_term.is_empty()
|
||||
{
|
||||
let mut modifier_text = String::new();
|
||||
if self.grid.search_results.has_modifiers_set() {
|
||||
let mut modifiers = Vec::new();
|
||||
modifier_text.push_str(" [");
|
||||
if self.grid.search_results.case_insensitive {
|
||||
modifiers.push("c")
|
||||
}
|
||||
if self.grid.search_results.whole_word_only {
|
||||
modifiers.push("o")
|
||||
}
|
||||
if self.grid.search_results.wrap_search {
|
||||
modifiers.push("w")
|
||||
}
|
||||
modifier_text.push_str(&modifiers.join(", "));
|
||||
modifier_text.push(']');
|
||||
}
|
||||
format!("SEARCHING: {}{}", self.search_term, modifier_text)
|
||||
} else if self.pane_name.is_empty() {
|
||||
self.grid
|
||||
.title
|
||||
@ -264,6 +317,7 @@ impl Pane for TerminalPane {
|
||||
} else {
|
||||
self.pane_name.clone()
|
||||
};
|
||||
|
||||
let frame = PaneFrame::new(
|
||||
self.current_geom().into(),
|
||||
self.grid.scrollback_position_and_length(),
|
||||
@ -495,10 +549,60 @@ impl Pane for TerminalPane {
|
||||
fn mouse_mode(&self) -> bool {
|
||||
self.grid.mouse_mode
|
||||
}
|
||||
|
||||
fn get_line_number(&self) -> Option<usize> {
|
||||
// + 1 because the absolute position in the scrollback is 0 indexed and this should be 1 indexed
|
||||
Some(self.grid.absolute_position_in_scrollback() + 1)
|
||||
}
|
||||
|
||||
fn update_search_term(&mut self, needle: &str) {
|
||||
match needle {
|
||||
"\0" => {
|
||||
self.search_term = String::new();
|
||||
},
|
||||
"\u{007F}" | "\u{0008}" => {
|
||||
//delete and backspace keys
|
||||
self.search_term.pop();
|
||||
},
|
||||
c => {
|
||||
self.search_term.push_str(c);
|
||||
},
|
||||
}
|
||||
self.grid.clear_search();
|
||||
if !self.search_term.is_empty() {
|
||||
self.grid.set_search_string(&self.search_term);
|
||||
}
|
||||
self.set_should_render(true);
|
||||
}
|
||||
fn search_down(&mut self) {
|
||||
if self.search_term.is_empty() {
|
||||
return; // No-op
|
||||
}
|
||||
self.grid.search_down();
|
||||
self.set_should_render(true);
|
||||
}
|
||||
fn search_up(&mut self) {
|
||||
if self.search_term.is_empty() {
|
||||
return; // No-op
|
||||
}
|
||||
self.grid.search_up();
|
||||
self.set_should_render(true);
|
||||
}
|
||||
fn toggle_search_case_sensitivity(&mut self) {
|
||||
self.grid.toggle_search_case_sensitivity();
|
||||
self.set_should_render(true);
|
||||
}
|
||||
fn toggle_search_whole_words(&mut self) {
|
||||
self.grid.toggle_search_whole_words();
|
||||
self.set_should_render(true);
|
||||
}
|
||||
fn toggle_search_wrap(&mut self) {
|
||||
self.grid.toggle_search_wrap();
|
||||
}
|
||||
fn clear_search(&mut self) {
|
||||
self.grid.clear_search();
|
||||
self.search_term.clear();
|
||||
}
|
||||
}
|
||||
|
||||
impl TerminalPane {
|
||||
@ -542,6 +646,7 @@ impl TerminalPane {
|
||||
prev_pane_name: pane_name,
|
||||
borderless: false,
|
||||
fake_cursor_locations: HashSet::new(),
|
||||
search_term: String::new(),
|
||||
}
|
||||
}
|
||||
pub fn get_x(&self) -> usize {
|
||||
@ -586,3 +691,7 @@ impl TerminalPane {
|
||||
#[cfg(test)]
|
||||
#[path = "./unit/terminal_pane_tests.rs"]
|
||||
mod grid_tests;
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "./unit/search_in_pane_tests.rs"]
|
||||
mod search_tests;
|
||||
|
413
zellij-server/src/panes/unit/search_in_pane_tests.rs
Normal file
413
zellij-server/src/panes/unit/search_in_pane_tests.rs
Normal file
@ -0,0 +1,413 @@
|
||||
use super::super::TerminalPane;
|
||||
use crate::panes::sixel::SixelImageStore;
|
||||
use crate::panes::LinkHandler;
|
||||
use crate::tab::Pane;
|
||||
use insta::assert_snapshot;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::rc::Rc;
|
||||
use zellij_utils::data::{Palette, Style};
|
||||
use zellij_utils::pane_size::PaneGeom;
|
||||
|
||||
fn read_fixture() -> Vec<u8> {
|
||||
let mut path_to_file = std::path::PathBuf::new();
|
||||
path_to_file.push("../src");
|
||||
path_to_file.push("tests");
|
||||
path_to_file.push("fixtures");
|
||||
path_to_file.push("grid_copy");
|
||||
std::fs::read(path_to_file)
|
||||
.unwrap_or_else(|_| panic!("could not read fixture ../src/tests/fixtures/grid_copy"))
|
||||
}
|
||||
|
||||
fn create_pane() -> TerminalPane {
|
||||
let mut fake_win_size = PaneGeom::default();
|
||||
fake_win_size.cols.set_inner(121);
|
||||
fake_win_size.rows.set_inner(20);
|
||||
|
||||
let pid = 1;
|
||||
let style = Style::default();
|
||||
let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
|
||||
let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
|
||||
let mut terminal_pane = TerminalPane::new(
|
||||
pid,
|
||||
fake_win_size,
|
||||
style,
|
||||
0,
|
||||
String::new(),
|
||||
Rc::new(RefCell::new(LinkHandler::new())),
|
||||
Rc::new(RefCell::new(None)),
|
||||
sixel_image_store,
|
||||
Rc::new(RefCell::new(Palette::default())),
|
||||
terminal_emulator_color_codes,
|
||||
); // 0 is the pane index
|
||||
let content = read_fixture();
|
||||
terminal_pane.handle_pty_bytes(content);
|
||||
terminal_pane
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn searching_inside_a_viewport() {
|
||||
let mut terminal_pane = create_pane();
|
||||
terminal_pane.update_search_term("tortor");
|
||||
assert_snapshot!(
|
||||
"grid_copy_tortor_highlighted",
|
||||
format!("{:?}", terminal_pane.grid)
|
||||
);
|
||||
terminal_pane.search_up();
|
||||
// snapshot-size optimization: We use a named one here to de-duplicate
|
||||
assert_snapshot!(
|
||||
"grid_copy_search_cursor_at_bottom",
|
||||
format!("{:?}", terminal_pane.grid)
|
||||
);
|
||||
terminal_pane.search_up();
|
||||
assert_snapshot!(
|
||||
"grid_copy_search_cursor_at_second",
|
||||
format!("{:?}", terminal_pane.grid)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn searching_scroll_viewport() {
|
||||
let mut terminal_pane = create_pane();
|
||||
terminal_pane.update_search_term("tortor");
|
||||
terminal_pane.search_up();
|
||||
// snapshot-size optimization: We use a named one here to de-duplicate
|
||||
assert_snapshot!(
|
||||
"grid_copy_search_cursor_at_bottom",
|
||||
format!("{:?}", terminal_pane.grid)
|
||||
);
|
||||
terminal_pane.search_up();
|
||||
assert_snapshot!(
|
||||
"grid_copy_search_cursor_at_second",
|
||||
format!("{:?}", terminal_pane.grid)
|
||||
);
|
||||
// Scroll away
|
||||
terminal_pane.search_up();
|
||||
assert_snapshot!(
|
||||
"grid_copy_search_scrolled_up",
|
||||
format!("{:?}", terminal_pane.grid)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn searching_with_wrap() {
|
||||
let mut terminal_pane = create_pane();
|
||||
// Searching for "tortor"
|
||||
terminal_pane.update_search_term("tortor");
|
||||
// Selecting the last place tortor was found
|
||||
terminal_pane.search_up();
|
||||
assert_snapshot!(
|
||||
"grid_copy_search_cursor_at_bottom",
|
||||
format!("{:?}", terminal_pane.grid)
|
||||
);
|
||||
// Search backwards again
|
||||
terminal_pane.search_up();
|
||||
assert_snapshot!(
|
||||
"grid_copy_search_cursor_at_second",
|
||||
format!("{:?}", terminal_pane.grid)
|
||||
);
|
||||
terminal_pane.search_down();
|
||||
assert_snapshot!(
|
||||
"grid_copy_search_cursor_at_bottom",
|
||||
format!("{:?}", terminal_pane.grid)
|
||||
);
|
||||
// Searching forward again should do nothing here
|
||||
terminal_pane.search_down();
|
||||
assert_snapshot!(
|
||||
"grid_copy_search_cursor_at_bottom",
|
||||
format!("{:?}", terminal_pane.grid)
|
||||
);
|
||||
// Only after wrapping search is active, do we actually jump in the scroll buffer
|
||||
terminal_pane.toggle_search_wrap();
|
||||
terminal_pane.search_down();
|
||||
assert_snapshot!(
|
||||
"grid_copy_search_cursor_at_top",
|
||||
format!("{:?}", terminal_pane.grid)
|
||||
);
|
||||
|
||||
// Deactivate wrap again
|
||||
terminal_pane.toggle_search_wrap();
|
||||
// Should be a no-op again
|
||||
terminal_pane.search_up();
|
||||
assert_snapshot!(
|
||||
"grid_copy_search_cursor_at_top",
|
||||
format!("{:?}", terminal_pane.grid)
|
||||
);
|
||||
|
||||
// Re-activate wrap again
|
||||
terminal_pane.toggle_search_wrap();
|
||||
terminal_pane.search_up();
|
||||
assert_snapshot!(
|
||||
"grid_copy_search_cursor_at_bottom",
|
||||
format!("{:?}", terminal_pane.grid)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn searching_case_insensitive() {
|
||||
let mut terminal_pane = create_pane();
|
||||
terminal_pane.update_search_term("quam");
|
||||
assert_snapshot!(
|
||||
"grid_copy_quam_highlighted",
|
||||
format!("{:?}", terminal_pane.grid)
|
||||
);
|
||||
|
||||
// sensitivity off
|
||||
terminal_pane.toggle_search_case_sensitivity();
|
||||
|
||||
assert_snapshot!(
|
||||
"grid_copy_quam_insensitive_highlighted",
|
||||
format!("{:?}", terminal_pane.grid)
|
||||
);
|
||||
|
||||
// sensitivity on
|
||||
terminal_pane.toggle_search_case_sensitivity();
|
||||
|
||||
assert_snapshot!(
|
||||
"grid_copy_quam_highlighted",
|
||||
format!("{:?}", terminal_pane.grid)
|
||||
);
|
||||
|
||||
// Select one and check that we keep the current selection,
|
||||
// if it wasn't one that vanished
|
||||
terminal_pane.search_up();
|
||||
assert_snapshot!(
|
||||
"grid_copy_quam_highlighted_cursor_bottom",
|
||||
format!("{:?}", terminal_pane.grid)
|
||||
);
|
||||
|
||||
// sensitivity off
|
||||
terminal_pane.toggle_search_case_sensitivity();
|
||||
|
||||
assert_snapshot!(
|
||||
"grid_copy_quam_insensitive_cursor_bottom",
|
||||
format!("{:?}", terminal_pane.grid)
|
||||
);
|
||||
|
||||
// sensitivity on
|
||||
terminal_pane.toggle_search_case_sensitivity();
|
||||
|
||||
assert_snapshot!(
|
||||
"grid_copy_quam_highlighted_cursor_bottom",
|
||||
format!("{:?}", terminal_pane.grid)
|
||||
);
|
||||
|
||||
// sensitivity off
|
||||
terminal_pane.toggle_search_case_sensitivity();
|
||||
|
||||
// Selecting the case insensitive result
|
||||
terminal_pane.search_up();
|
||||
terminal_pane.search_up();
|
||||
terminal_pane.search_up();
|
||||
terminal_pane.search_up();
|
||||
terminal_pane.search_up();
|
||||
assert_snapshot!(
|
||||
"grid_copy_quam_insensitive_selection",
|
||||
format!("{:?}", terminal_pane.grid)
|
||||
);
|
||||
|
||||
// sensitivity on
|
||||
terminal_pane.toggle_search_case_sensitivity();
|
||||
// Now the selected result vanished and we should be back at
|
||||
// the beginning
|
||||
assert_snapshot!(
|
||||
"grid_copy_quam_highlighted",
|
||||
format!("{:?}", terminal_pane.grid)
|
||||
);
|
||||
terminal_pane.search_up();
|
||||
assert_snapshot!(
|
||||
"grid_copy_quam_highlighted_cursor_bottom",
|
||||
format!("{:?}", terminal_pane.grid)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn searching_inside_and_scroll() {
|
||||
let fake_client_id = 1;
|
||||
let mut terminal_pane = create_pane();
|
||||
terminal_pane.update_search_term("quam");
|
||||
terminal_pane.search_up();
|
||||
assert_snapshot!(
|
||||
"grid_copy_quam_highlighted_cursor_bottom",
|
||||
format!("{:?}", terminal_pane.grid)
|
||||
);
|
||||
assert_eq!(
|
||||
terminal_pane.grid.search_results.active.as_ref(),
|
||||
terminal_pane.grid.search_results.selections.last()
|
||||
);
|
||||
// Scrolling up until a new search result appears
|
||||
terminal_pane.scroll_up(4, fake_client_id);
|
||||
|
||||
// Scrolling back down should give the same result as before
|
||||
terminal_pane.scroll_down(4, fake_client_id);
|
||||
assert_eq!(
|
||||
terminal_pane.grid.search_results.active.as_ref(),
|
||||
terminal_pane.grid.search_results.selections.last()
|
||||
);
|
||||
assert_snapshot!(
|
||||
"grid_copy_quam_highlighted_cursor_bottom",
|
||||
format!("{:?}", terminal_pane.grid)
|
||||
);
|
||||
|
||||
// Scrolling up until a the active marker goes out of view
|
||||
terminal_pane.scroll_up(5, fake_client_id);
|
||||
assert_eq!(terminal_pane.grid.search_results.active, None);
|
||||
|
||||
terminal_pane.scroll_down(5, fake_client_id);
|
||||
assert_eq!(terminal_pane.grid.search_results.active, None);
|
||||
assert_snapshot!(
|
||||
"grid_copy_quam_highlighted",
|
||||
format!("{:?}", terminal_pane.grid)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn searching_and_resize() {
|
||||
let mut terminal_pane = create_pane();
|
||||
terminal_pane.update_search_term("tortor");
|
||||
assert_snapshot!(
|
||||
"grid_copy_tortor_highlighted",
|
||||
format!("{:?}", terminal_pane.grid)
|
||||
);
|
||||
|
||||
// Highlights should still be there, if pane gets resized
|
||||
terminal_pane.grid.change_size(20, 150);
|
||||
assert_snapshot!(
|
||||
"grid_copy_tortor_highlighted_wide",
|
||||
format!("{:?}", terminal_pane.grid)
|
||||
);
|
||||
|
||||
terminal_pane.grid.change_size(20, 80);
|
||||
assert_snapshot!(
|
||||
"grid_copy_tortor_highlighted_narrow",
|
||||
format!("{:?}", terminal_pane.grid)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn searching_across_line_wrap() {
|
||||
let mut terminal_pane = create_pane();
|
||||
terminal_pane.update_search_term("aliquam sem fringilla");
|
||||
// Spread across two lines
|
||||
terminal_pane.grid.change_size(30, 60);
|
||||
assert_snapshot!(
|
||||
"grid_copy_multiline_highlighted",
|
||||
format!("{:?}", terminal_pane.grid)
|
||||
);
|
||||
|
||||
// Spread across 4 lines
|
||||
terminal_pane.grid.change_size(40, 4);
|
||||
assert_snapshot!(
|
||||
"grid_copy_multiline_highlighted_narrow",
|
||||
format!("{:?}", terminal_pane.grid)
|
||||
);
|
||||
|
||||
terminal_pane.search_up();
|
||||
assert_snapshot!(
|
||||
"grid_copy_multiline_selected_narrow",
|
||||
format!("{:?}", terminal_pane.grid)
|
||||
);
|
||||
|
||||
// Wrap on
|
||||
terminal_pane.toggle_search_wrap();
|
||||
terminal_pane.search_down();
|
||||
assert_snapshot!(
|
||||
"grid_copy_multiline_selected_wrap_narrow",
|
||||
format!("{:?}", terminal_pane.grid)
|
||||
);
|
||||
|
||||
// Wrap off
|
||||
terminal_pane.toggle_search_wrap();
|
||||
// Don't forget the current selection
|
||||
terminal_pane.search_up();
|
||||
assert_snapshot!(
|
||||
"grid_copy_multiline_selected_wrap_narrow",
|
||||
format!("{:?}", terminal_pane.grid)
|
||||
);
|
||||
|
||||
// Wrap on
|
||||
terminal_pane.toggle_search_wrap();
|
||||
terminal_pane.search_up();
|
||||
assert_snapshot!(
|
||||
"grid_copy_multiline_selected_narrow",
|
||||
format!("{:?}", terminal_pane.grid)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn searching_whole_word() {
|
||||
let mut terminal_pane = create_pane();
|
||||
terminal_pane.update_search_term("quam");
|
||||
assert_snapshot!(
|
||||
"grid_copy_quam_highlighted",
|
||||
format!("{:?}", terminal_pane.grid)
|
||||
);
|
||||
|
||||
terminal_pane.toggle_search_whole_words();
|
||||
assert_snapshot!(
|
||||
"grid_copy_quam_whole_word_only",
|
||||
format!("{:?}", terminal_pane.grid)
|
||||
);
|
||||
|
||||
terminal_pane.toggle_search_whole_words();
|
||||
assert_snapshot!(
|
||||
"grid_copy_quam_highlighted",
|
||||
format!("{:?}", terminal_pane.grid)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn searching_whole_word_across_line_wrap() {
|
||||
let mut terminal_pane = create_pane();
|
||||
terminal_pane.handle_pty_bytes(
|
||||
"a:--:aaaaaaaaa:--:--:--:aaaaaaaaaaa:--: :--: :--: aaa :--::--: aaa"
|
||||
.as_bytes()
|
||||
.to_vec(),
|
||||
);
|
||||
terminal_pane.grid.change_size(20, 5);
|
||||
terminal_pane.update_search_term(":--:");
|
||||
assert_snapshot!(
|
||||
"grid_copy_multiline_not_whole_word",
|
||||
format!("{:?}", terminal_pane.grid)
|
||||
);
|
||||
|
||||
terminal_pane.toggle_search_whole_words();
|
||||
assert_snapshot!(
|
||||
"grid_copy_multiline_whole_word",
|
||||
format!("{:?}", terminal_pane.grid)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn searching_whole_word_case_insensitive() {
|
||||
let mut terminal_pane = create_pane();
|
||||
terminal_pane.update_search_term("quam");
|
||||
assert_snapshot!(
|
||||
"grid_copy_quam_highlighted",
|
||||
format!("{:?}", terminal_pane.grid)
|
||||
);
|
||||
|
||||
terminal_pane.toggle_search_whole_words();
|
||||
assert_snapshot!(
|
||||
"grid_copy_quam_whole_word_only",
|
||||
format!("{:?}", terminal_pane.grid)
|
||||
);
|
||||
|
||||
terminal_pane.toggle_search_case_sensitivity();
|
||||
assert_snapshot!(
|
||||
"grid_copy_quam_whole_word_case_insensitive",
|
||||
format!("{:?}", terminal_pane.grid)
|
||||
);
|
||||
|
||||
terminal_pane.toggle_search_whole_words();
|
||||
assert_snapshot!(
|
||||
"grid_copy_quam_insensitive_highlighted",
|
||||
format!("{:?}", terminal_pane.grid)
|
||||
);
|
||||
|
||||
terminal_pane.toggle_search_case_sensitivity();
|
||||
assert_snapshot!(
|
||||
"grid_copy_quam_highlighted",
|
||||
format!("{:?}", terminal_pane.grid)
|
||||
);
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
---
|
||||
source: zellij-server/src/panes/./unit/search_in_pane_tests.rs
|
||||
expression: "format!(\"{:?}\", terminal_pane.grid)"
|
||||
---
|
||||
00 (W): d elementum tempus egestas sed sed risus pretium quam vulput
|
||||
01 (W): ate. Turpis egestas maecenas pharetra convallis. Arcu cursus
|
||||
02 (W): vitae congue mauris rhoncus aenean vel. Augue ut lectus arc
|
||||
03 (W): u bibendum. Scelerisque varius morbi enim nunc faucibus a pe
|
||||
04 (W): llentesque. Mattis pellentesque id nibh tortor id aliquet le
|
||||
05 (W): ctus proin nibh. In ##################### ut. Urna et pharet
|
||||
06 (W): ra pharetra massa massa ultricies mi. Enim nulla aliquet por
|
||||
07 (W): ttitor lacus luctus accumsan tortor posuere. Malesuada fames
|
||||
08 (W): ac turpis egestas integer. Venenatis tellus in metus vulput
|
||||
09 (W): ate eu scelerisque felis. Suspendisse faucibus interdum posu
|
||||
10 (W): ere lorem ipsum dolor sit amet.
|
||||
11 (C):
|
||||
12 (C): Quam elementum pulvinar etiam non quam lacus suspendisse fau
|
||||
13 (W): cibus. Egestas sed sed risus pretium quam vulputate dignissi
|
||||
14 (W): m suspendisse. Risus nec feugiat in fermentum posuere urna.
|
||||
15 (W): Vestibulum lorem sed risus ultricies. Egestas maecenas phare
|
||||
16 (W): tra convallis posuere morbi. Egestas tellus rutrum tellus pe
|
||||
17 (W): llentesque. Pulvinar etiam non quam lacus suspendisse faucib
|
||||
18 (W): us. Lectus proin nibh nisl condimentum id venenatis a condim
|
||||
19 (W): entum. Adipiscing elit pellentesque habitant morbi tristique
|
||||
20 (W): senectus et netus. Nunc id cursus metus aliquam eleifend. U
|
||||
21 (W): rna nec tincidunt praesent semper feugiat nibh sed pulvinar.
|
||||
22 (W): Donec ultrices tincidunt arcu non sodales neque sodales ut
|
||||
23 (W): etiam. Suspendisse sed nisi lacus sed viverra tellus in hac
|
||||
24 (W): habitasse. Nunc scelerisque viverra mauris in ##############
|
||||
25 (W): #######.
|
||||
26 (C): ⏎
|
||||
27 (C): zellij on mouse-support [?] is 📦 v0.14.0 via 🦀 v1.53.0-b
|
||||
28 (W): eta.3
|
||||
29 (C): ❯
|
||||
|
@ -0,0 +1,45 @@
|
||||
---
|
||||
source: zellij-server/src/panes/./unit/search_in_pane_tests.rs
|
||||
expression: "format!(\"{:?}\", terminal_pane.grid)"
|
||||
---
|
||||
00 (W): a te
|
||||
01 (W): llus
|
||||
02 (W): in
|
||||
03 (W): hac
|
||||
04 (W): habi
|
||||
05 (W): tass
|
||||
06 (W): e. N
|
||||
07 (W): unc
|
||||
08 (W): scel
|
||||
09 (W): eris
|
||||
10 (W): que
|
||||
11 (W): vive
|
||||
12 (W): rra
|
||||
13 (W): maur
|
||||
14 (W): is i
|
||||
15 (W): n ##
|
||||
16 (W): ####
|
||||
17 (W): ####
|
||||
18 (W): ####
|
||||
19 (W): ####
|
||||
20 (W): ###.
|
||||
21 (C): ⏎
|
||||
22 (C): zell
|
||||
23 (W): ij o
|
||||
24 (W): n
|
||||
25 (W): mous
|
||||
26 (W): e-su
|
||||
27 (W): ppor
|
||||
28 (W): t [?
|
||||
29 (W): ] is
|
||||
30 (W): 📦
|
||||
31 (W): v0.1
|
||||
32 (W): 4.0
|
||||
33 (W): via
|
||||
34 (W): 🦀 v
|
||||
35 (W): 1.53
|
||||
36 (W): .0-b
|
||||
37 (W): eta.
|
||||
38 (W): 3
|
||||
39 (C): ❯
|
||||
|
@ -0,0 +1,25 @@
|
||||
---
|
||||
source: zellij-server/src/panes/./unit/search_in_pane_tests.rs
|
||||
expression: "format!(\"{:?}\", terminal_pane.grid)"
|
||||
---
|
||||
00 (W): v0.1
|
||||
01 (W): 4.0 v
|
||||
02 (W): ia 🦀
|
||||
03 (W): v1.5
|
||||
04 (W): 3.0-b
|
||||
05 (W): eta.3
|
||||
06 (C): ❯ a##
|
||||
07 (W): ##aaa
|
||||
08 (W): aaaaa
|
||||
09 (W): a####
|
||||
10 (W): --###
|
||||
11 (W): #aaaa
|
||||
12 (W): aaaaa
|
||||
13 (W): aa###
|
||||
14 (W): # ###
|
||||
15 (W): # ###
|
||||
16 (W): # aaa
|
||||
17 (W): ####
|
||||
18 (W): ####
|
||||
19 (W): aaa
|
||||
|
@ -0,0 +1,45 @@
|
||||
---
|
||||
source: zellij-server/src/panes/./unit/search_in_pane_tests.rs
|
||||
expression: "format!(\"{:?}\", terminal_pane.grid)"
|
||||
---
|
||||
00 (W): a te
|
||||
01 (W): llus
|
||||
02 (W): in
|
||||
03 (W): hac
|
||||
04 (W): habi
|
||||
05 (W): tass
|
||||
06 (W): e. N
|
||||
07 (W): unc
|
||||
08 (W): scel
|
||||
09 (W): eris
|
||||
10 (W): que
|
||||
11 (W): vive
|
||||
12 (W): rra
|
||||
13 (W): maur
|
||||
14 (W): is i
|
||||
15 (W): n __
|
||||
16 (W): ____
|
||||
17 (W): ____
|
||||
18 (W): ____
|
||||
19 (W): ____
|
||||
20 (W): ___.
|
||||
21 (C): ⏎
|
||||
22 (C): zell
|
||||
23 (W): ij o
|
||||
24 (W): n
|
||||
25 (W): mous
|
||||
26 (W): e-su
|
||||
27 (W): ppor
|
||||
28 (W): t [?
|
||||
29 (W): ] is
|
||||
30 (W): 📦
|
||||
31 (W): v0.1
|
||||
32 (W): 4.0
|
||||
33 (W): via
|
||||
34 (W): 🦀 v
|
||||
35 (W): 1.53
|
||||
36 (W): .0-b
|
||||
37 (W): eta.
|
||||
38 (W): 3
|
||||
39 (C): ❯
|
||||
|
@ -0,0 +1,45 @@
|
||||
---
|
||||
source: zellij-server/src/panes/./unit/search_in_pane_tests.rs
|
||||
expression: "format!(\"{:?}\", terminal_pane.grid)"
|
||||
---
|
||||
00 (W): n __
|
||||
01 (W): ____
|
||||
02 (W): ____
|
||||
03 (W): ____
|
||||
04 (W): ____
|
||||
05 (W): ___
|
||||
06 (W): ut.
|
||||
07 (C): Vulp
|
||||
08 (W): utat
|
||||
09 (W): e eu
|
||||
10 (W): sce
|
||||
11 (W): leri
|
||||
12 (W): sque
|
||||
13 (W): fel
|
||||
14 (W): is i
|
||||
15 (W): mper
|
||||
16 (W): diet
|
||||
17 (W): pro
|
||||
18 (W): in f
|
||||
19 (W): erme
|
||||
20 (W): ntum
|
||||
21 (W): leo
|
||||
22 (W): .
|
||||
23 (C): Curs
|
||||
24 (W): us r
|
||||
25 (W): isus
|
||||
26 (W): at
|
||||
27 (W): ultr
|
||||
28 (W): ices
|
||||
29 (W): mi
|
||||
30 (W): temp
|
||||
31 (W): us.
|
||||
32 (C): Laor
|
||||
33 (W): eet
|
||||
34 (W): id d
|
||||
35 (W): onec
|
||||
36 (W): ult
|
||||
37 (W): rice
|
||||
38 (W): s ti
|
||||
39 (W): ncid
|
||||
|
@ -0,0 +1,25 @@
|
||||
---
|
||||
source: zellij-server/src/panes/./unit/search_in_pane_tests.rs
|
||||
expression: "format!(\"{:?}\", terminal_pane.grid)"
|
||||
---
|
||||
00 (W): v0.1
|
||||
01 (W): 4.0 v
|
||||
02 (W): ia 🦀
|
||||
03 (W): v1.5
|
||||
04 (W): 3.0-b
|
||||
05 (W): eta.3
|
||||
06 (C): ❯ a:-
|
||||
07 (W): -:aaa
|
||||
08 (W): aaaaa
|
||||
09 (W): a:--#
|
||||
10 (W): ###--
|
||||
11 (W): :aaaa
|
||||
12 (W): aaaaa
|
||||
13 (W): aa:--
|
||||
14 (W): : ###
|
||||
15 (W): # ###
|
||||
16 (W): # aaa
|
||||
17 (W): ####
|
||||
18 (W): ####
|
||||
19 (W): aaa
|
||||
|
@ -0,0 +1,25 @@
|
||||
---
|
||||
source: zellij-server/src/panes/./unit/search_in_pane_tests.rs
|
||||
expression: "format!(\"{:?}\", terminal_pane.grid)"
|
||||
---
|
||||
00 (C):
|
||||
01 (C): Quisque id diam vel ####. Id porta nibh venenatis cras sed felis eget velit aliquet. Sagittis ali#### malesuada bibendum
|
||||
02 (W): arcu. Libero id faucibus nisl tincidunt eget nullam non. Sed elementum tempus egestas sed sed risus pretium #### vulputat
|
||||
03 (W): e. Turpis egestas maecenas pharetra convallis. Arcu cursus vitae congue mauris rhoncus aenean vel. Augue ut lectus arcu b
|
||||
04 (W): ibendum. Scelerisque varius morbi enim nunc faucibus a pellentesque. Mattis pellentesque id nibh tortor id aliquet lectus
|
||||
05 (W): proin nibh. In ali#### sem fringilla ut. Urna et pharetra pharetra massa massa ultricies mi. Enim nulla aliquet porttito
|
||||
06 (W): r lacus luctus accumsan tortor posuere. Malesuada fames ac turpis egestas integer. Venenatis tellus in metus vulputate eu
|
||||
07 (W): scelerisque felis. Suspendisse faucibus interdum posuere lorem ipsum dolor sit amet.
|
||||
08 (C):
|
||||
09 (C): Quam elementum pulvinar etiam non #### lacus suspendisse faucibus. Egestas sed sed risus pretium #### vulputate dignissim
|
||||
10 (W): suspendisse. Risus nec feugiat in fermentum posuere urna. Vestibulum lorem sed risus ultricies. Egestas maecenas pharetr
|
||||
11 (W): a convallis posuere morbi. Egestas tellus rutrum tellus pellentesque. Pulvinar etiam non #### lacus suspendisse faucibus.
|
||||
12 (W): Lectus proin nibh nisl condimentum id venenatis a condimentum. Adipiscing elit pellentesque habitant morbi tristique sen
|
||||
13 (W): ectus et netus. Nunc id cursus metus ali#### eleifend. Urna nec tincidunt praesent semper feugiat nibh sed pulvinar. Done
|
||||
14 (W): c ultrices tincidunt arcu non sodales neque sodales ut etiam. Suspendisse sed nisi lacus sed viverra tellus in hac habita
|
||||
15 (W): sse. Nunc scelerisque viverra mauris in ali#### sem fringilla.
|
||||
16 (C): ⏎
|
||||
17 (W):
|
||||
18 (C): zellij on mouse-support [?] is 📦 v0.14.0 via 🦀 v1.53.0-beta.3
|
||||
19 (C): ❯
|
||||
|
@ -0,0 +1,25 @@
|
||||
---
|
||||
source: zellij-server/src/panes/./unit/search_in_pane_tests.rs
|
||||
expression: "format!(\"{:?}\", terminal_pane.grid)"
|
||||
---
|
||||
00 (C):
|
||||
01 (C): Quisque id diam vel ####. Id porta nibh venenatis cras sed felis eget velit aliquet. Sagittis ali#### malesuada bibendum
|
||||
02 (W): arcu. Libero id faucibus nisl tincidunt eget nullam non. Sed elementum tempus egestas sed sed risus pretium #### vulputat
|
||||
03 (W): e. Turpis egestas maecenas pharetra convallis. Arcu cursus vitae congue mauris rhoncus aenean vel. Augue ut lectus arcu b
|
||||
04 (W): ibendum. Scelerisque varius morbi enim nunc faucibus a pellentesque. Mattis pellentesque id nibh tortor id aliquet lectus
|
||||
05 (W): proin nibh. In ali#### sem fringilla ut. Urna et pharetra pharetra massa massa ultricies mi. Enim nulla aliquet porttito
|
||||
06 (W): r lacus luctus accumsan tortor posuere. Malesuada fames ac turpis egestas integer. Venenatis tellus in metus vulputate eu
|
||||
07 (W): scelerisque felis. Suspendisse faucibus interdum posuere lorem ipsum dolor sit amet.
|
||||
08 (C):
|
||||
09 (C): Quam elementum pulvinar etiam non #### lacus suspendisse faucibus. Egestas sed sed risus pretium #### vulputate dignissim
|
||||
10 (W): suspendisse. Risus nec feugiat in fermentum posuere urna. Vestibulum lorem sed risus ultricies. Egestas maecenas pharetr
|
||||
11 (W): a convallis posuere morbi. Egestas tellus rutrum tellus pellentesque. Pulvinar etiam non #### lacus suspendisse faucibus.
|
||||
12 (W): Lectus proin nibh nisl condimentum id venenatis a condimentum. Adipiscing elit pellentesque habitant morbi tristique sen
|
||||
13 (W): ectus et netus. Nunc id cursus metus ali#### eleifend. Urna nec tincidunt praesent semper feugiat nibh sed pulvinar. Done
|
||||
14 (W): c ultrices tincidunt arcu non sodales neque sodales ut etiam. Suspendisse sed nisi lacus sed viverra tellus in hac habita
|
||||
15 (W): sse. Nunc scelerisque viverra mauris in ali____ sem fringilla.
|
||||
16 (C): ⏎
|
||||
17 (W):
|
||||
18 (C): zellij on mouse-support [?] is 📦 v0.14.0 via 🦀 v1.53.0-beta.3
|
||||
19 (C): ❯
|
||||
|
@ -0,0 +1,25 @@
|
||||
---
|
||||
source: zellij-server/src/panes/./unit/search_in_pane_tests.rs
|
||||
expression: "format!(\"{:?}\", terminal_pane.grid)"
|
||||
---
|
||||
00 (C):
|
||||
01 (C): Quisque id diam vel ####. Id porta nibh venenatis cras sed felis eget velit aliquet. Sagittis ali#### malesuada bibendum
|
||||
02 (W): arcu. Libero id faucibus nisl tincidunt eget nullam non. Sed elementum tempus egestas sed sed risus pretium #### vulputat
|
||||
03 (W): e. Turpis egestas maecenas pharetra convallis. Arcu cursus vitae congue mauris rhoncus aenean vel. Augue ut lectus arcu b
|
||||
04 (W): ibendum. Scelerisque varius morbi enim nunc faucibus a pellentesque. Mattis pellentesque id nibh tortor id aliquet lectus
|
||||
05 (W): proin nibh. In ali#### sem fringilla ut. Urna et pharetra pharetra massa massa ultricies mi. Enim nulla aliquet porttito
|
||||
06 (W): r lacus luctus accumsan tortor posuere. Malesuada fames ac turpis egestas integer. Venenatis tellus in metus vulputate eu
|
||||
07 (W): scelerisque felis. Suspendisse faucibus interdum posuere lorem ipsum dolor sit amet.
|
||||
08 (C):
|
||||
09 (C): #### elementum pulvinar etiam non #### lacus suspendisse faucibus. Egestas sed sed risus pretium #### vulputate dignissim
|
||||
10 (W): suspendisse. Risus nec feugiat in fermentum posuere urna. Vestibulum lorem sed risus ultricies. Egestas maecenas pharetr
|
||||
11 (W): a convallis posuere morbi. Egestas tellus rutrum tellus pellentesque. Pulvinar etiam non #### lacus suspendisse faucibus.
|
||||
12 (W): Lectus proin nibh nisl condimentum id venenatis a condimentum. Adipiscing elit pellentesque habitant morbi tristique sen
|
||||
13 (W): ectus et netus. Nunc id cursus metus ali#### eleifend. Urna nec tincidunt praesent semper feugiat nibh sed pulvinar. Done
|
||||
14 (W): c ultrices tincidunt arcu non sodales neque sodales ut etiam. Suspendisse sed nisi lacus sed viverra tellus in hac habita
|
||||
15 (W): sse. Nunc scelerisque viverra mauris in ali____ sem fringilla.
|
||||
16 (C): ⏎
|
||||
17 (W):
|
||||
18 (C): zellij on mouse-support [?] is 📦 v0.14.0 via 🦀 v1.53.0-beta.3
|
||||
19 (C): ❯
|
||||
|
@ -0,0 +1,25 @@
|
||||
---
|
||||
source: zellij-server/src/panes/./unit/search_in_pane_tests.rs
|
||||
expression: "format!(\"{:?}\", terminal_pane.grid)"
|
||||
---
|
||||
00 (C):
|
||||
01 (C): Quisque id diam vel ####. Id porta nibh venenatis cras sed felis eget velit aliquet. Sagittis ali#### malesuada bibendum
|
||||
02 (W): arcu. Libero id faucibus nisl tincidunt eget nullam non. Sed elementum tempus egestas sed sed risus pretium #### vulputat
|
||||
03 (W): e. Turpis egestas maecenas pharetra convallis. Arcu cursus vitae congue mauris rhoncus aenean vel. Augue ut lectus arcu b
|
||||
04 (W): ibendum. Scelerisque varius morbi enim nunc faucibus a pellentesque. Mattis pellentesque id nibh tortor id aliquet lectus
|
||||
05 (W): proin nibh. In ali#### sem fringilla ut. Urna et pharetra pharetra massa massa ultricies mi. Enim nulla aliquet porttito
|
||||
06 (W): r lacus luctus accumsan tortor posuere. Malesuada fames ac turpis egestas integer. Venenatis tellus in metus vulputate eu
|
||||
07 (W): scelerisque felis. Suspendisse faucibus interdum posuere lorem ipsum dolor sit amet.
|
||||
08 (C):
|
||||
09 (C): #### elementum pulvinar etiam non #### lacus suspendisse faucibus. Egestas sed sed risus pretium #### vulputate dignissim
|
||||
10 (W): suspendisse. Risus nec feugiat in fermentum posuere urna. Vestibulum lorem sed risus ultricies. Egestas maecenas pharetr
|
||||
11 (W): a convallis posuere morbi. Egestas tellus rutrum tellus pellentesque. Pulvinar etiam non #### lacus suspendisse faucibus.
|
||||
12 (W): Lectus proin nibh nisl condimentum id venenatis a condimentum. Adipiscing elit pellentesque habitant morbi tristique sen
|
||||
13 (W): ectus et netus. Nunc id cursus metus ali#### eleifend. Urna nec tincidunt praesent semper feugiat nibh sed pulvinar. Done
|
||||
14 (W): c ultrices tincidunt arcu non sodales neque sodales ut etiam. Suspendisse sed nisi lacus sed viverra tellus in hac habita
|
||||
15 (W): sse. Nunc scelerisque viverra mauris in ali#### sem fringilla.
|
||||
16 (C): ⏎
|
||||
17 (W):
|
||||
18 (C): zellij on mouse-support [?] is 📦 v0.14.0 via 🦀 v1.53.0-beta.3
|
||||
19 (C): ❯
|
||||
|
@ -0,0 +1,25 @@
|
||||
---
|
||||
source: zellij-server/src/panes/./unit/search_in_pane_tests.rs
|
||||
expression: "format!(\"{:?}\", terminal_pane.grid)"
|
||||
---
|
||||
00 (C):
|
||||
01 (C): Quisque id diam vel ####. Id porta nibh venenatis cras sed felis eget velit aliquet. Sagittis ali#### malesuada bibendum
|
||||
02 (W): arcu. Libero id faucibus nisl tincidunt eget nullam non. Sed elementum tempus egestas sed sed risus pretium #### vulputat
|
||||
03 (W): e. Turpis egestas maecenas pharetra convallis. Arcu cursus vitae congue mauris rhoncus aenean vel. Augue ut lectus arcu b
|
||||
04 (W): ibendum. Scelerisque varius morbi enim nunc faucibus a pellentesque. Mattis pellentesque id nibh tortor id aliquet lectus
|
||||
05 (W): proin nibh. In ali#### sem fringilla ut. Urna et pharetra pharetra massa massa ultricies mi. Enim nulla aliquet porttito
|
||||
06 (W): r lacus luctus accumsan tortor posuere. Malesuada fames ac turpis egestas integer. Venenatis tellus in metus vulputate eu
|
||||
07 (W): scelerisque felis. Suspendisse faucibus interdum posuere lorem ipsum dolor sit amet.
|
||||
08 (C):
|
||||
09 (C): ____ elementum pulvinar etiam non #### lacus suspendisse faucibus. Egestas sed sed risus pretium #### vulputate dignissim
|
||||
10 (W): suspendisse. Risus nec feugiat in fermentum posuere urna. Vestibulum lorem sed risus ultricies. Egestas maecenas pharetr
|
||||
11 (W): a convallis posuere morbi. Egestas tellus rutrum tellus pellentesque. Pulvinar etiam non #### lacus suspendisse faucibus.
|
||||
12 (W): Lectus proin nibh nisl condimentum id venenatis a condimentum. Adipiscing elit pellentesque habitant morbi tristique sen
|
||||
13 (W): ectus et netus. Nunc id cursus metus ali#### eleifend. Urna nec tincidunt praesent semper feugiat nibh sed pulvinar. Done
|
||||
14 (W): c ultrices tincidunt arcu non sodales neque sodales ut etiam. Suspendisse sed nisi lacus sed viverra tellus in hac habita
|
||||
15 (W): sse. Nunc scelerisque viverra mauris in ali#### sem fringilla.
|
||||
16 (C): ⏎
|
||||
17 (W):
|
||||
18 (C): zellij on mouse-support [?] is 📦 v0.14.0 via 🦀 v1.53.0-beta.3
|
||||
19 (C): ❯
|
||||
|
@ -0,0 +1,25 @@
|
||||
---
|
||||
source: zellij-server/src/panes/./unit/search_in_pane_tests.rs
|
||||
expression: "format!(\"{:?}\", terminal_pane.grid)"
|
||||
---
|
||||
00 (C):
|
||||
01 (C): Quisque id diam vel ####. Id porta nibh venenatis cras sed felis eget velit aliquet. Sagittis aliquam malesuada bibendum
|
||||
02 (W): arcu. Libero id faucibus nisl tincidunt eget nullam non. Sed elementum tempus egestas sed sed risus pretium #### vulputat
|
||||
03 (W): e. Turpis egestas maecenas pharetra convallis. Arcu cursus vitae congue mauris rhoncus aenean vel. Augue ut lectus arcu b
|
||||
04 (W): ibendum. Scelerisque varius morbi enim nunc faucibus a pellentesque. Mattis pellentesque id nibh tortor id aliquet lectus
|
||||
05 (W): proin nibh. In aliquam sem fringilla ut. Urna et pharetra pharetra massa massa ultricies mi. Enim nulla aliquet porttito
|
||||
06 (W): r lacus luctus accumsan tortor posuere. Malesuada fames ac turpis egestas integer. Venenatis tellus in metus vulputate eu
|
||||
07 (W): scelerisque felis. Suspendisse faucibus interdum posuere lorem ipsum dolor sit amet.
|
||||
08 (C):
|
||||
09 (C): #### elementum pulvinar etiam non #### lacus suspendisse faucibus. Egestas sed sed risus pretium #### vulputate dignissim
|
||||
10 (W): suspendisse. Risus nec feugiat in fermentum posuere urna. Vestibulum lorem sed risus ultricies. Egestas maecenas pharetr
|
||||
11 (W): a convallis posuere morbi. Egestas tellus rutrum tellus pellentesque. Pulvinar etiam non #### lacus suspendisse faucibus.
|
||||
12 (W): Lectus proin nibh nisl condimentum id venenatis a condimentum. Adipiscing elit pellentesque habitant morbi tristique sen
|
||||
13 (W): ectus et netus. Nunc id cursus metus aliquam eleifend. Urna nec tincidunt praesent semper feugiat nibh sed pulvinar. Done
|
||||
14 (W): c ultrices tincidunt arcu non sodales neque sodales ut etiam. Suspendisse sed nisi lacus sed viverra tellus in hac habita
|
||||
15 (W): sse. Nunc scelerisque viverra mauris in aliquam sem fringilla.
|
||||
16 (C): ⏎
|
||||
17 (W):
|
||||
18 (C): zellij on mouse-support [?] is 📦 v0.14.0 via 🦀 v1.53.0-beta.3
|
||||
19 (C): ❯
|
||||
|
@ -0,0 +1,25 @@
|
||||
---
|
||||
source: zellij-server/src/panes/./unit/search_in_pane_tests.rs
|
||||
expression: "format!(\"{:?}\", terminal_pane.grid)"
|
||||
---
|
||||
00 (C):
|
||||
01 (C): Quisque id diam vel ####. Id porta nibh venenatis cras sed felis eget velit aliquet. Sagittis aliquam malesuada bibendum
|
||||
02 (W): arcu. Libero id faucibus nisl tincidunt eget nullam non. Sed elementum tempus egestas sed sed risus pretium #### vulputat
|
||||
03 (W): e. Turpis egestas maecenas pharetra convallis. Arcu cursus vitae congue mauris rhoncus aenean vel. Augue ut lectus arcu b
|
||||
04 (W): ibendum. Scelerisque varius morbi enim nunc faucibus a pellentesque. Mattis pellentesque id nibh tortor id aliquet lectus
|
||||
05 (W): proin nibh. In aliquam sem fringilla ut. Urna et pharetra pharetra massa massa ultricies mi. Enim nulla aliquet porttito
|
||||
06 (W): r lacus luctus accumsan tortor posuere. Malesuada fames ac turpis egestas integer. Venenatis tellus in metus vulputate eu
|
||||
07 (W): scelerisque felis. Suspendisse faucibus interdum posuere lorem ipsum dolor sit amet.
|
||||
08 (C):
|
||||
09 (C): Quam elementum pulvinar etiam non #### lacus suspendisse faucibus. Egestas sed sed risus pretium #### vulputate dignissim
|
||||
10 (W): suspendisse. Risus nec feugiat in fermentum posuere urna. Vestibulum lorem sed risus ultricies. Egestas maecenas pharetr
|
||||
11 (W): a convallis posuere morbi. Egestas tellus rutrum tellus pellentesque. Pulvinar etiam non #### lacus suspendisse faucibus.
|
||||
12 (W): Lectus proin nibh nisl condimentum id venenatis a condimentum. Adipiscing elit pellentesque habitant morbi tristique sen
|
||||
13 (W): ectus et netus. Nunc id cursus metus aliquam eleifend. Urna nec tincidunt praesent semper feugiat nibh sed pulvinar. Done
|
||||
14 (W): c ultrices tincidunt arcu non sodales neque sodales ut etiam. Suspendisse sed nisi lacus sed viverra tellus in hac habita
|
||||
15 (W): sse. Nunc scelerisque viverra mauris in aliquam sem fringilla.
|
||||
16 (C): ⏎
|
||||
17 (W):
|
||||
18 (C): zellij on mouse-support [?] is 📦 v0.14.0 via 🦀 v1.53.0-beta.3
|
||||
19 (C): ❯
|
||||
|
@ -0,0 +1,25 @@
|
||||
---
|
||||
source: zellij-server/src/panes/./unit/search_in_pane_tests.rs
|
||||
expression: "format!(\"{:?}\", terminal_pane.grid)"
|
||||
---
|
||||
00 (C):
|
||||
01 (C): Quisque id diam vel quam. Id porta nibh venenatis cras sed felis eget velit aliquet. Sagittis aliquam malesuada bibendum
|
||||
02 (W): arcu. Libero id faucibus nisl tincidunt eget nullam non. Sed elementum tempus egestas sed sed risus pretium quam vulputat
|
||||
03 (W): e. Turpis egestas maecenas pharetra convallis. Arcu cursus vitae congue mauris rhoncus aenean vel. Augue ut lectus arcu b
|
||||
04 (W): ibendum. Scelerisque varius morbi enim nunc faucibus a pellentesque. Mattis pellentesque id nibh ###### id aliquet lectus
|
||||
05 (W): proin nibh. In aliquam sem fringilla ut. Urna et pharetra pharetra massa massa ultricies mi. Enim nulla aliquet porttito
|
||||
06 (W): r lacus luctus accumsan ______ posuere. Malesuada fames ac turpis egestas integer. Venenatis tellus in metus vulputate eu
|
||||
07 (W): scelerisque felis. Suspendisse faucibus interdum posuere lorem ipsum dolor sit amet.
|
||||
08 (C):
|
||||
09 (C): Quam elementum pulvinar etiam non quam lacus suspendisse faucibus. Egestas sed sed risus pretium quam vulputate dignissim
|
||||
10 (W): suspendisse. Risus nec feugiat in fermentum posuere urna. Vestibulum lorem sed risus ultricies. Egestas maecenas pharetr
|
||||
11 (W): a convallis posuere morbi. Egestas tellus rutrum tellus pellentesque. Pulvinar etiam non quam lacus suspendisse faucibus.
|
||||
12 (W): Lectus proin nibh nisl condimentum id venenatis a condimentum. Adipiscing elit pellentesque habitant morbi tristique sen
|
||||
13 (W): ectus et netus. Nunc id cursus metus aliquam eleifend. Urna nec tincidunt praesent semper feugiat nibh sed pulvinar. Done
|
||||
14 (W): c ultrices tincidunt arcu non sodales neque sodales ut etiam. Suspendisse sed nisi lacus sed viverra tellus in hac habita
|
||||
15 (W): sse. Nunc scelerisque viverra mauris in aliquam sem fringilla.
|
||||
16 (C): ⏎
|
||||
17 (W):
|
||||
18 (C): zellij on mouse-support [?] is 📦 v0.14.0 via 🦀 v1.53.0-beta.3
|
||||
19 (C): ❯
|
||||
|
@ -0,0 +1,25 @@
|
||||
---
|
||||
source: zellij-server/src/panes/./unit/search_in_pane_tests.rs
|
||||
expression: "format!(\"{:?}\", terminal_pane.grid)"
|
||||
---
|
||||
00 (C):
|
||||
01 (C): Quisque id diam vel quam. Id porta nibh venenatis cras sed felis eget velit aliquet. Sagittis aliquam malesuada bibendum
|
||||
02 (W): arcu. Libero id faucibus nisl tincidunt eget nullam non. Sed elementum tempus egestas sed sed risus pretium quam vulputat
|
||||
03 (W): e. Turpis egestas maecenas pharetra convallis. Arcu cursus vitae congue mauris rhoncus aenean vel. Augue ut lectus arcu b
|
||||
04 (W): ibendum. Scelerisque varius morbi enim nunc faucibus a pellentesque. Mattis pellentesque id nibh ______ id aliquet lectus
|
||||
05 (W): proin nibh. In aliquam sem fringilla ut. Urna et pharetra pharetra massa massa ultricies mi. Enim nulla aliquet porttito
|
||||
06 (W): r lacus luctus accumsan ###### posuere. Malesuada fames ac turpis egestas integer. Venenatis tellus in metus vulputate eu
|
||||
07 (W): scelerisque felis. Suspendisse faucibus interdum posuere lorem ipsum dolor sit amet.
|
||||
08 (C):
|
||||
09 (C): Quam elementum pulvinar etiam non quam lacus suspendisse faucibus. Egestas sed sed risus pretium quam vulputate dignissim
|
||||
10 (W): suspendisse. Risus nec feugiat in fermentum posuere urna. Vestibulum lorem sed risus ultricies. Egestas maecenas pharetr
|
||||
11 (W): a convallis posuere morbi. Egestas tellus rutrum tellus pellentesque. Pulvinar etiam non quam lacus suspendisse faucibus.
|
||||
12 (W): Lectus proin nibh nisl condimentum id venenatis a condimentum. Adipiscing elit pellentesque habitant morbi tristique sen
|
||||
13 (W): ectus et netus. Nunc id cursus metus aliquam eleifend. Urna nec tincidunt praesent semper feugiat nibh sed pulvinar. Done
|
||||
14 (W): c ultrices tincidunt arcu non sodales neque sodales ut etiam. Suspendisse sed nisi lacus sed viverra tellus in hac habita
|
||||
15 (W): sse. Nunc scelerisque viverra mauris in aliquam sem fringilla.
|
||||
16 (C): ⏎
|
||||
17 (W):
|
||||
18 (C): zellij on mouse-support [?] is 📦 v0.14.0 via 🦀 v1.53.0-beta.3
|
||||
19 (C): ❯
|
||||
|
@ -0,0 +1,25 @@
|
||||
---
|
||||
source: zellij-server/src/panes/./unit/search_in_pane_tests.rs
|
||||
expression: "format!(\"{:?}\", terminal_pane.grid)"
|
||||
---
|
||||
00 (C): Velit ut ______ pretium viverra suspendisse potenti nullam ac ######. Adipiscing elit ut aliquam purus sit amet luctus ve
|
||||
01 (W): nenatis.
|
||||
02 (C): Duis ut diam quam nulla porttitor massa id neque aliquam. Suspendisse potenti nullam ac ###### vitae purus faucibus ornar
|
||||
03 (W): e suspendisse.
|
||||
04 (C): Vitae nunc sed velit dignissim sodales ut eu sem integer.
|
||||
05 (C): Tortor id aliquet lectus proin nibh nisl.
|
||||
06 (C): Commodo odio aenean sed adipiscing diam donec adipiscing tristique risus.
|
||||
07 (C): Velit dignissim sodales ut eu sem. Lacus suspendisse faucibus interdum posuere lorem. Ac placerat vestibulum lectus mauri
|
||||
08 (W): s ultrices eros. Elementum integer enim neque volutpat ac. Augue interdum velit euismod in.
|
||||
09 (C):
|
||||
10 (C): Egestas sed sed risus pretium quam vulputate dignissim.
|
||||
11 (C): Gravida rutrum quisque non tellus orci ac auctor augue.
|
||||
12 (C): Risus nec feugiat in fermentum posuere urna nec tincidunt praesent.
|
||||
13 (C): Elementum eu facilisis sed odio morbi quis.
|
||||
14 (C): Mattis ullamcorper velit sed ullamcorper morbi.
|
||||
15 (C): Dui vivamus arcu felis bibendum. Sit amet aliquam id diam.
|
||||
16 (C): Suscipit tellus mauris a diam maecenas sed enim.
|
||||
17 (C): Odio ut sem nulla pharetra.
|
||||
18 (C): Cras ornare arcu dui vivamus arcu felis bibendum.
|
||||
19 (C): Egestas fringilla phasellus faucibus scelerisque eleifend.
|
||||
|
@ -0,0 +1,25 @@
|
||||
---
|
||||
source: zellij-server/src/panes/./unit/search_in_pane_tests.rs
|
||||
expression: "format!(\"{:?}\", terminal_pane.grid)"
|
||||
---
|
||||
00 (C): Rutrum tellus pellentesque eu tincidunt ______ aliquam nulla.
|
||||
01 (C):
|
||||
02 (C): Nascetur ridiculus mus mauris vitae ultricies leo integer malesuada.
|
||||
03 (C): Interdum posuere lorem ipsum dolor sit amet consectetur.
|
||||
04 (C): Porta non pulvinar neque laoreet suspendisse interdum.
|
||||
05 (C): Fames ac turpis egestas integer eget aliquet nibh praesent.
|
||||
06 (C): Congue nisi vitae suscipit tellus mauris a diam maecenas sed.
|
||||
07 (C): Nec ultrices dui sapien eget mi proin sed libero enim.
|
||||
08 (C): Tellus rutrum tellus pellentesque eu tincidunt.
|
||||
09 (C): Ultrices eros in cursus turpis massa tincidunt dui ut ornare.
|
||||
10 (C): Arcu cursus vitae congue mauris rhoncus aenean vel elit scelerisque.
|
||||
11 (C): Viverra mauris in aliquam sem fringilla ut.
|
||||
12 (C): Vulputate eu scelerisque felis imperdiet proin fermentum leo.
|
||||
13 (C): Cursus risus at ultrices mi tempus.
|
||||
14 (C): Laoreet id donec ultrices tincidunt arcu non sodales.
|
||||
15 (C): Amet dictum sit amet justo donec enim.
|
||||
16 (C): Hac habitasse platea dictumst vestibulum rhoncus est pellentesque.
|
||||
17 (C): Facilisi cras fermentum odio eu feugiat.
|
||||
18 (C): Elit ut aliquam purus sit amet luctus venenatis lectus.
|
||||
19 (C): Dignissim enim sit amet venenatis urna cursus.
|
||||
|
@ -0,0 +1,25 @@
|
||||
---
|
||||
source: zellij-server/src/panes/./unit/search_in_pane_tests.rs
|
||||
expression: "format!(\"{:?}\", terminal_pane.grid)"
|
||||
---
|
||||
00 (C):
|
||||
01 (C): Quisque id diam vel quam. Id porta nibh venenatis cras sed felis eget velit aliquet. Sagittis aliquam malesuada bibendum
|
||||
02 (W): arcu. Libero id faucibus nisl tincidunt eget nullam non. Sed elementum tempus egestas sed sed risus pretium quam vulputat
|
||||
03 (W): e. Turpis egestas maecenas pharetra convallis. Arcu cursus vitae congue mauris rhoncus aenean vel. Augue ut lectus arcu b
|
||||
04 (W): ibendum. Scelerisque varius morbi enim nunc faucibus a pellentesque. Mattis pellentesque id nibh ###### id aliquet lectus
|
||||
05 (W): proin nibh. In aliquam sem fringilla ut. Urna et pharetra pharetra massa massa ultricies mi. Enim nulla aliquet porttito
|
||||
06 (W): r lacus luctus accumsan ###### posuere. Malesuada fames ac turpis egestas integer. Venenatis tellus in metus vulputate eu
|
||||
07 (W): scelerisque felis. Suspendisse faucibus interdum posuere lorem ipsum dolor sit amet.
|
||||
08 (C):
|
||||
09 (C): Quam elementum pulvinar etiam non quam lacus suspendisse faucibus. Egestas sed sed risus pretium quam vulputate dignissim
|
||||
10 (W): suspendisse. Risus nec feugiat in fermentum posuere urna. Vestibulum lorem sed risus ultricies. Egestas maecenas pharetr
|
||||
11 (W): a convallis posuere morbi. Egestas tellus rutrum tellus pellentesque. Pulvinar etiam non quam lacus suspendisse faucibus.
|
||||
12 (W): Lectus proin nibh nisl condimentum id venenatis a condimentum. Adipiscing elit pellentesque habitant morbi tristique sen
|
||||
13 (W): ectus et netus. Nunc id cursus metus aliquam eleifend. Urna nec tincidunt praesent semper feugiat nibh sed pulvinar. Done
|
||||
14 (W): c ultrices tincidunt arcu non sodales neque sodales ut etiam. Suspendisse sed nisi lacus sed viverra tellus in hac habita
|
||||
15 (W): sse. Nunc scelerisque viverra mauris in aliquam sem fringilla.
|
||||
16 (C): ⏎
|
||||
17 (W):
|
||||
18 (C): zellij on mouse-support [?] is 📦 v0.14.0 via 🦀 v1.53.0-beta.3
|
||||
19 (C): ❯
|
||||
|
@ -0,0 +1,25 @@
|
||||
---
|
||||
source: zellij-server/src/panes/./unit/search_in_pane_tests.rs
|
||||
expression: "format!(\"{:?}\", terminal_pane.grid)"
|
||||
---
|
||||
00 (W): m nunc faucibus a pellentesque. Mattis pellentesque id nibh ###### id aliquet le
|
||||
01 (W): ctus proin nibh. In aliquam sem fringilla ut. Urna et pharetra pharetra massa ma
|
||||
02 (W): ssa ultricies mi. Enim nulla aliquet porttitor lacus luctus accumsan ###### posu
|
||||
03 (W): ere. Malesuada fames ac turpis egestas integer. Venenatis tellus in metus vulput
|
||||
04 (W): ate eu scelerisque felis. Suspendisse faucibus interdum posuere lorem ipsum dolo
|
||||
05 (W): r sit amet.
|
||||
06 (C):
|
||||
07 (C): Quam elementum pulvinar etiam non quam lacus suspendisse faucibus. Egestas sed s
|
||||
08 (W): ed risus pretium quam vulputate dignissim suspendisse. Risus nec feugiat in ferm
|
||||
09 (W): entum posuere urna. Vestibulum lorem sed risus ultricies. Egestas maecenas phare
|
||||
10 (W): tra convallis posuere morbi. Egestas tellus rutrum tellus pellentesque. Pulvinar
|
||||
11 (W): etiam non quam lacus suspendisse faucibus. Lectus proin nibh nisl condimentum i
|
||||
12 (W): d venenatis a condimentum. Adipiscing elit pellentesque habitant morbi tristique
|
||||
13 (W): senectus et netus. Nunc id cursus metus aliquam eleifend. Urna nec tincidunt pr
|
||||
14 (W): aesent semper feugiat nibh sed pulvinar. Donec ultrices tincidunt arcu non sodal
|
||||
15 (W): es neque sodales ut etiam. Suspendisse sed nisi lacus sed viverra tellus in hac
|
||||
16 (W): habitasse. Nunc scelerisque viverra mauris in aliquam sem fringilla.
|
||||
17 (C): ⏎
|
||||
18 (C): zellij on mouse-support [?] is 📦 v0.14.0 via 🦀 v1.53.0-beta.3
|
||||
19 (C): ❯
|
||||
|
@ -0,0 +1,25 @@
|
||||
---
|
||||
source: zellij-server/src/panes/./unit/search_in_pane_tests.rs
|
||||
expression: "format!(\"{:?}\", terminal_pane.grid)"
|
||||
---
|
||||
00 (C): Dignissim enim sit amet venenatis urna cursus.
|
||||
01 (C): Amet consectetur adipiscing elit ut aliquam purus.
|
||||
02 (C): Elementum pulvinar etiam non quam lacus suspendisse.
|
||||
03 (C):
|
||||
04 (C): Quisque id diam vel quam. Id porta nibh venenatis cras sed felis eget velit aliquet. Sagittis aliquam malesuada bibendum arcu. Libero id faucibus nisl
|
||||
05 (W): tincidunt eget nullam non. Sed elementum tempus egestas sed sed risus pretium quam vulputate. Turpis egestas maecenas pharetra convallis. Arcu cursus
|
||||
06 (W): vitae congue mauris rhoncus aenean vel. Augue ut lectus arcu bibendum. Scelerisque varius morbi enim nunc faucibus a pellentesque. Mattis pellentesqu
|
||||
07 (W): e id nibh ###### id aliquet lectus proin nibh. In aliquam sem fringilla ut. Urna et pharetra pharetra massa massa ultricies mi. Enim nulla aliquet por
|
||||
08 (W): ttitor lacus luctus accumsan ###### posuere. Malesuada fames ac turpis egestas integer. Venenatis tellus in metus vulputate eu scelerisque felis. Susp
|
||||
09 (W): endisse faucibus interdum posuere lorem ipsum dolor sit amet.
|
||||
10 (C):
|
||||
11 (C): Quam elementum pulvinar etiam non quam lacus suspendisse faucibus. Egestas sed sed risus pretium quam vulputate dignissim suspendisse. Risus nec feugi
|
||||
12 (W): at in fermentum posuere urna. Vestibulum lorem sed risus ultricies. Egestas maecenas pharetra convallis posuere morbi. Egestas tellus rutrum tellus pe
|
||||
13 (W): llentesque. Pulvinar etiam non quam lacus suspendisse faucibus. Lectus proin nibh nisl condimentum id venenatis a condimentum. Adipiscing elit pellent
|
||||
14 (W): esque habitant morbi tristique senectus et netus. Nunc id cursus metus aliquam eleifend. Urna nec tincidunt praesent semper feugiat nibh sed pulvinar.
|
||||
15 (W): Donec ultrices tincidunt arcu non sodales neque sodales ut etiam. Suspendisse sed nisi lacus sed viverra tellus in hac habitasse. Nunc scelerisque vi
|
||||
16 (W): verra mauris in aliquam sem fringilla.
|
||||
17 (C): ⏎
|
||||
18 (C): zellij on mouse-support [?] is 📦 v0.14.0 via 🦀 v1.53.0-beta.3
|
||||
19 (C): ❯
|
||||
|
@ -11,7 +11,7 @@ use zellij_utils::{
|
||||
channels::SenderWithContext,
|
||||
data::Event,
|
||||
input::{
|
||||
actions::{Action, Direction, ResizeDirection},
|
||||
actions::{Action, Direction, ResizeDirection, SearchDirection, SearchOption},
|
||||
command::TerminalAction,
|
||||
get_mode_info,
|
||||
},
|
||||
@ -417,6 +417,29 @@ fn route_action(
|
||||
_ => {},
|
||||
},
|
||||
Action::NoOp => {},
|
||||
Action::SearchInput(c) => {
|
||||
session
|
||||
.senders
|
||||
.send_to_screen(ScreenInstruction::UpdateSearch(c, client_id))
|
||||
.unwrap();
|
||||
},
|
||||
Action::Search(d) => {
|
||||
let instruction = match d {
|
||||
SearchDirection::Down => ScreenInstruction::SearchDown(client_id),
|
||||
SearchDirection::Up => ScreenInstruction::SearchUp(client_id),
|
||||
};
|
||||
session.senders.send_to_screen(instruction).unwrap();
|
||||
},
|
||||
Action::SearchToggleOption(o) => {
|
||||
let instruction = match o {
|
||||
SearchOption::CaseSensitivity => {
|
||||
ScreenInstruction::SearchToggleCaseSensitivity(client_id)
|
||||
},
|
||||
SearchOption::WholeWord => ScreenInstruction::SearchToggleWholeWord(client_id),
|
||||
SearchOption::Wrap => ScreenInstruction::SearchToggleWrap(client_id),
|
||||
};
|
||||
session.senders.send_to_screen(instruction).unwrap();
|
||||
},
|
||||
}
|
||||
should_break
|
||||
}
|
||||
|
@ -31,6 +31,29 @@ use zellij_utils::{
|
||||
ipc::{ClientAttributes, PixelDimensions},
|
||||
};
|
||||
|
||||
/// Get the active tab and call a closure on it
|
||||
///
|
||||
/// If no active tab can be found, an error is logged instead.
|
||||
///
|
||||
/// # Parameters
|
||||
///
|
||||
/// - screen: An instance of `Screen` to operate on
|
||||
/// - client_id: The client_id, usually taken from the `ScreenInstruction` that's being processed
|
||||
/// - closure: A closure satisfying `|tab: &mut Tab| -> ()`
|
||||
macro_rules! active_tab {
|
||||
($screen:ident, $client_id:ident, $closure:expr) => {
|
||||
if let Some(active_tab) = $screen.get_active_tab_mut($client_id) {
|
||||
// This could be made more ergonomic by declaring the type of 'active_tab' in the
|
||||
// closure, known as "Type Ascription". Then we could hint the type here and forego the
|
||||
// "&mut Tab" in all the closures below...
|
||||
// See: https://github.com/rust-lang/rust/issues/23416
|
||||
$closure(active_tab);
|
||||
} else {
|
||||
log::error!("Active tab not found for client id: {:?}", $client_id);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Instructions that can be sent to the [`Screen`].
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum ScreenInstruction {
|
||||
@ -109,6 +132,12 @@ pub enum ScreenInstruction {
|
||||
RemoveOverlay(ClientId),
|
||||
ConfirmPrompt(ClientId),
|
||||
DenyPrompt(ClientId),
|
||||
UpdateSearch(Vec<u8>, ClientId),
|
||||
SearchDown(ClientId),
|
||||
SearchUp(ClientId),
|
||||
SearchToggleCaseSensitivity(ClientId),
|
||||
SearchToggleWholeWord(ClientId),
|
||||
SearchToggleWrap(ClientId),
|
||||
}
|
||||
|
||||
impl From<&ScreenInstruction> for ScreenContext {
|
||||
@ -203,6 +232,14 @@ impl From<&ScreenInstruction> for ScreenContext {
|
||||
ScreenInstruction::RemoveOverlay(..) => ScreenContext::RemoveOverlay,
|
||||
ScreenInstruction::ConfirmPrompt(..) => ScreenContext::ConfirmPrompt,
|
||||
ScreenInstruction::DenyPrompt(..) => ScreenContext::DenyPrompt,
|
||||
ScreenInstruction::UpdateSearch(..) => ScreenContext::UpdateSearch,
|
||||
ScreenInstruction::SearchDown(..) => ScreenContext::SearchDown,
|
||||
ScreenInstruction::SearchUp(..) => ScreenContext::SearchUp,
|
||||
ScreenInstruction::SearchToggleCaseSensitivity(..) => {
|
||||
ScreenContext::SearchToggleCaseSensitivity
|
||||
},
|
||||
ScreenInstruction::SearchToggleWholeWord(..) => ScreenContext::SearchToggleWholeWord,
|
||||
ScreenInstruction::SearchToggleWrap(..) => ScreenContext::SearchToggleWrap,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -777,6 +814,14 @@ impl Screen {
|
||||
.unwrap_or(&self.default_mode_info)
|
||||
.mode;
|
||||
|
||||
// If we leave the Search-related modes, we need to clear all previous searches
|
||||
let search_related_modes = [InputMode::EnterSearch, InputMode::Search, InputMode::Scroll];
|
||||
if search_related_modes.contains(&previous_mode)
|
||||
&& !search_related_modes.contains(&mode_info.mode)
|
||||
{
|
||||
active_tab!(self, client_id, |tab: &mut Tab| tab.clear_search(client_id));
|
||||
}
|
||||
|
||||
if previous_mode == InputMode::Scroll
|
||||
&& (mode_info.mode == InputMode::Normal || mode_info.mode == InputMode::Locked)
|
||||
{
|
||||
@ -845,29 +890,6 @@ impl Screen {
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the active tab and call a closure on it
|
||||
///
|
||||
/// If no active tab can be found, an error is logged instead.
|
||||
///
|
||||
/// # Parameters
|
||||
///
|
||||
/// - screen: An instance of `Screen` to operate on
|
||||
/// - client_id: The client_id, usually taken from the `ScreenInstruction` that's being processed
|
||||
/// - closure: A closure satisfying `|tab: &mut Tab| -> ()`
|
||||
macro_rules! active_tab {
|
||||
($screen:ident, $client_id:ident, $closure:expr) => {
|
||||
if let Some(active_tab) = $screen.get_active_tab_mut($client_id) {
|
||||
// This could be made more ergonomic by declaring the type of 'active_tab' in the
|
||||
// closure, known as "Type Ascription". Then we could hint the type here and forego the
|
||||
// "&mut Tab" in all the closures below...
|
||||
// See: https://github.com/rust-lang/rust/issues/23416
|
||||
$closure(active_tab);
|
||||
} else {
|
||||
log::error!("Active tab not found for client id: {:?}", $client_id);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// The box is here in order to make the
|
||||
// NewClient enum smaller
|
||||
#[allow(clippy::boxed_local)]
|
||||
@ -1334,6 +1356,35 @@ pub(crate) fn screen_thread_main(
|
||||
screen.render();
|
||||
screen.unblock_input();
|
||||
},
|
||||
ScreenInstruction::UpdateSearch(c, client_id) => {
|
||||
active_tab!(screen, client_id, |tab: &mut Tab| tab
|
||||
.update_search_term(c, client_id));
|
||||
screen.render();
|
||||
},
|
||||
ScreenInstruction::SearchDown(client_id) => {
|
||||
active_tab!(screen, client_id, |tab: &mut Tab| tab
|
||||
.search_down(client_id));
|
||||
screen.render();
|
||||
},
|
||||
ScreenInstruction::SearchUp(client_id) => {
|
||||
active_tab!(screen, client_id, |tab: &mut Tab| tab.search_up(client_id));
|
||||
screen.render();
|
||||
},
|
||||
ScreenInstruction::SearchToggleCaseSensitivity(client_id) => {
|
||||
active_tab!(screen, client_id, |tab: &mut Tab| tab
|
||||
.toggle_search_case_sensitivity(client_id));
|
||||
screen.render();
|
||||
},
|
||||
ScreenInstruction::SearchToggleWrap(client_id) => {
|
||||
active_tab!(screen, client_id, |tab: &mut Tab| tab
|
||||
.toggle_search_wrap(client_id));
|
||||
screen.render();
|
||||
},
|
||||
ScreenInstruction::SearchToggleWholeWord(client_id) => {
|
||||
active_tab!(screen, client_id, |tab: &mut Tab| tab
|
||||
.toggle_search_whole_words(client_id));
|
||||
screen.render();
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -298,6 +298,27 @@ pub trait Pane {
|
||||
fn get_line_number(&self) -> Option<usize> {
|
||||
None
|
||||
}
|
||||
fn update_search_term(&mut self, _needle: &str) {
|
||||
// No-op by default (only terminal-panes currently have search capability)
|
||||
}
|
||||
fn search_down(&mut self) {
|
||||
// No-op by default (only terminal-panes currently have search capability)
|
||||
}
|
||||
fn search_up(&mut self) {
|
||||
// No-op by default (only terminal-panes currently have search capability)
|
||||
}
|
||||
fn toggle_search_case_sensitivity(&mut self) {
|
||||
// No-op by default (only terminal-panes currently have search capability)
|
||||
}
|
||||
fn toggle_search_whole_words(&mut self) {
|
||||
// No-op by default (only terminal-panes currently have search capability)
|
||||
}
|
||||
fn toggle_search_wrap(&mut self) {
|
||||
// No-op by default (only terminal-panes currently have search capability)
|
||||
}
|
||||
fn clear_search(&mut self) {
|
||||
// No-op by default (only terminal-panes currently have search capability)
|
||||
}
|
||||
}
|
||||
|
||||
impl Tab {
|
||||
@ -946,6 +967,7 @@ impl Tab {
|
||||
});
|
||||
}
|
||||
pub fn write_to_active_terminal(&mut self, input_bytes: Vec<u8>, client_id: ClientId) {
|
||||
self.clear_search(client_id); // this is an inexpensive operation if empty, if we need more such cleanups we should consider moving this and the rest to some sort of cleanup method
|
||||
let pane_id = if self.floating_panes.panes_are_visible() {
|
||||
self.floating_panes
|
||||
.get_active_pane_id(client_id)
|
||||
@ -2022,6 +2044,53 @@ impl Tab {
|
||||
pub fn panes_to_hide_count(&self) -> usize {
|
||||
self.tiled_panes.panes_to_hide_count()
|
||||
}
|
||||
|
||||
pub fn update_search_term(&mut self, buf: Vec<u8>, client_id: ClientId) {
|
||||
if let Some(active_pane) = self.get_active_pane_or_floating_pane_mut(client_id) {
|
||||
// It only allows printable unicode, delete and backspace keys.
|
||||
let is_updatable = buf.iter().all(|u| matches!(u, 0x20..=0x7E | 0x08 | 0x7F));
|
||||
if is_updatable {
|
||||
let s = str::from_utf8(&buf).unwrap();
|
||||
active_pane.update_search_term(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn search_down(&mut self, client_id: ClientId) {
|
||||
if let Some(active_pane) = self.get_active_pane_or_floating_pane_mut(client_id) {
|
||||
active_pane.search_down();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn search_up(&mut self, client_id: ClientId) {
|
||||
if let Some(active_pane) = self.get_active_pane_or_floating_pane_mut(client_id) {
|
||||
active_pane.search_up();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn toggle_search_case_sensitivity(&mut self, client_id: ClientId) {
|
||||
if let Some(active_pane) = self.get_active_pane_or_floating_pane_mut(client_id) {
|
||||
active_pane.toggle_search_case_sensitivity();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn toggle_search_wrap(&mut self, client_id: ClientId) {
|
||||
if let Some(active_pane) = self.get_active_pane_or_floating_pane_mut(client_id) {
|
||||
active_pane.toggle_search_wrap();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn toggle_search_whole_words(&mut self, client_id: ClientId) {
|
||||
if let Some(active_pane) = self.get_active_pane_or_floating_pane_mut(client_id) {
|
||||
active_pane.toggle_search_whole_words();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clear_search(&mut self, client_id: ClientId) {
|
||||
if let Some(active_pane) = self.get_active_pane_or_floating_pane_mut(client_id) {
|
||||
active_pane.clear_search();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -0,0 +1,26 @@
|
||||
---
|
||||
source: zellij-server/src/tab/./unit/tab_integration_tests.rs
|
||||
assertion_line: 1721
|
||||
expression: snapshot
|
||||
---
|
||||
00 (C):
|
||||
01 (C):
|
||||
02 (C):
|
||||
03 (C):
|
||||
04 (C):
|
||||
05 (C): ┌ SEARCHING: fring ──────────────────────── SCROLL: 0/103 ┐
|
||||
06 (C): │ │
|
||||
07 (C): │a mauris in aliquam sem fringilla. │
|
||||
08 (C): │ │
|
||||
09 (C): │ │
|
||||
10 (C): │ │
|
||||
11 (C): │ │
|
||||
12 (C): │ │
|
||||
13 (C): │ │
|
||||
14 (C): └──────────────────────────────────────────────────────────┘
|
||||
15 (C):
|
||||
16 (C):
|
||||
17 (C):
|
||||
18 (C):
|
||||
19 (C):
|
||||
|
@ -0,0 +1,25 @@
|
||||
---
|
||||
source: zellij-server/src/tab/./unit/tab_integration_tests.rs
|
||||
expression: snapshot
|
||||
---
|
||||
00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||||
01 (C): │ │
|
||||
02 (C): │ │
|
||||
03 (C): │ │
|
||||
04 (C): │ │
|
||||
05 (C): │ ┌ fish /home/thomas/Projects/zellij ─────── SCROLL: 0/103 ┐ │
|
||||
06 (C): │ │d viverra tellus in hac habitasse. Nunc scelerisque viverr│ │
|
||||
07 (C): │ │a mauris in aliquam sem fringilla. │ │
|
||||
08 (C): │ │⏎ │ │
|
||||
09 (C): │ │ │ │
|
||||
10 (C): │ │ │ │
|
||||
11 (C): │ │zellij on mouse-support [?] is 📦 v0.14.0 via 🦀 v1.53.0│ │
|
||||
12 (C): │ │-beta.3 │ │
|
||||
13 (C): │ │❯ │ │
|
||||
14 (C): │ └──────────────────────────────────────────────────────────┘ │
|
||||
15 (C): │ │
|
||||
16 (C): │ │
|
||||
17 (C): │ │
|
||||
18 (C): │ │
|
||||
19 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
|
@ -0,0 +1,25 @@
|
||||
---
|
||||
source: zellij-server/src/tab/./unit/tab_integration_tests.rs
|
||||
expression: snapshot
|
||||
---
|
||||
00 (C): ┌ SEARCHING: tortor ───────────────────────────────────────────────────────────────────────────────────── SCROLL: 0/58 ┐
|
||||
01 (C): │ │
|
||||
02 (C): │ │
|
||||
03 (C): │arcu bibendum. Scelerisque varius morbi enim nunc faucibus a pellentesque. Mattis pellentesque id nibh tortor id alique│
|
||||
04 (C): │ │
|
||||
05 (C): │t porttitor lacus luctus accumsan tortor posuere. Malesuada fames ac turpis egestas integer. Venenatis tellus in metus │
|
||||
06 (C): │ │
|
||||
07 (C): │ │
|
||||
08 (C): │ │
|
||||
09 (C): │ │
|
||||
10 (C): │ │
|
||||
11 (C): │ │
|
||||
12 (C): │ │
|
||||
13 (C): │ │
|
||||
14 (C): │ │
|
||||
15 (C): │ │
|
||||
16 (C): │ │
|
||||
17 (C): │ │
|
||||
18 (C): │ │
|
||||
19 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
|
@ -0,0 +1,25 @@
|
||||
---
|
||||
source: zellij-server/src/tab/./unit/tab_integration_tests.rs
|
||||
expression: snapshot
|
||||
---
|
||||
00 (C): ┌ SEARCHING: tortor [c, o, w] ─────────────────────────────────────────────────────────────────────────── SCROLL: 0/58 ┐
|
||||
01 (C): │ │
|
||||
02 (C): │ │
|
||||
03 (C): │arcu bibendum. Scelerisque varius morbi enim nunc faucibus a pellentesque. Mattis pellentesque id nibh tortor id alique│
|
||||
04 (C): │ │
|
||||
05 (C): │t porttitor lacus luctus accumsan tortor posuere. Malesuada fames ac turpis egestas integer. Venenatis tellus in metus │
|
||||
06 (C): │ │
|
||||
07 (C): │ │
|
||||
08 (C): │ │
|
||||
09 (C): │ │
|
||||
10 (C): │ │
|
||||
11 (C): │ │
|
||||
12 (C): │ │
|
||||
13 (C): │ │
|
||||
14 (C): │ │
|
||||
15 (C): │ │
|
||||
16 (C): │ │
|
||||
17 (C): │ │
|
||||
18 (C): │ │
|
||||
19 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
|
@ -0,0 +1,25 @@
|
||||
---
|
||||
source: zellij-server/src/tab/./unit/tab_integration_tests.rs
|
||||
expression: snapshot
|
||||
---
|
||||
00 (C): ┌ fish /home/thomas/Projects/zellij ───────────────────────────────────────────────────────────────────── SCROLL: 0/58 ┐
|
||||
01 (C): │m arcu. Libero id faucibus nisl tincidunt eget nullam non. Sed elementum tempus egestas sed sed risus pretium quam vulp│
|
||||
02 (C): │utate. Turpis egestas maecenas pharetra convallis. Arcu cursus vitae congue mauris rhoncus aenean vel. Augue ut lectus │
|
||||
03 (C): │arcu bibendum. Scelerisque varius morbi enim nunc faucibus a pellentesque. Mattis pellentesque id nibh tortor id alique│
|
||||
04 (C): │t lectus proin nibh. In aliquam sem fringilla ut. Urna et pharetra pharetra massa massa ultricies mi. Enim nulla alique│
|
||||
05 (C): │t porttitor lacus luctus accumsan tortor posuere. Malesuada fames ac turpis egestas integer. Venenatis tellus in metus │
|
||||
06 (C): │vulputate eu scelerisque felis. Suspendisse faucibus interdum posuere lorem ipsum dolor sit amet. │
|
||||
07 (C): │ │
|
||||
08 (C): │Quam elementum pulvinar etiam non quam lacus suspendisse faucibus. Egestas sed sed risus pretium quam vulputate digniss│
|
||||
09 (C): │im suspendisse. Risus nec feugiat in fermentum posuere urna. Vestibulum lorem sed risus ultricies. Egestas maecenas pha│
|
||||
10 (C): │retra convallis posuere morbi. Egestas tellus rutrum tellus pellentesque. Pulvinar etiam non quam lacus suspendisse fau│
|
||||
11 (C): │cibus. Lectus proin nibh nisl condimentum id venenatis a condimentum. Adipiscing elit pellentesque habitant morbi trist│
|
||||
12 (C): │ique senectus et netus. Nunc id cursus metus aliquam eleifend. Urna nec tincidunt praesent semper feugiat nibh sed pulv│
|
||||
13 (C): │inar. Donec ultrices tincidunt arcu non sodales neque sodales ut etiam. Suspendisse sed nisi lacus sed viverra tellus i│
|
||||
14 (C): │n hac habitasse. Nunc scelerisque viverra mauris in aliquam sem fringilla. │
|
||||
15 (C): │⏎ │
|
||||
16 (C): │ │
|
||||
17 (C): │zellij on mouse-support [?] is 📦 v0.14.0 via 🦀 v1.53.0-beta.3 │
|
||||
18 (C): │❯ │
|
||||
19 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
|
@ -25,7 +25,7 @@ use std::rc::Rc;
|
||||
use zellij_utils::nix;
|
||||
|
||||
use zellij_utils::{
|
||||
data::{ModeInfo, Palette, Style},
|
||||
data::{InputMode, ModeInfo, Palette, Style},
|
||||
input::command::TerminalAction,
|
||||
interprocess::local_socket::LocalSocketStream,
|
||||
ipc::{ClientToServerMsg, ServerToClientMsg},
|
||||
@ -98,7 +98,7 @@ impl ServerOsApi for FakeInputOutput {
|
||||
}
|
||||
|
||||
// TODO: move to shared thingy with other test file
|
||||
fn create_new_tab(size: Size) -> Tab {
|
||||
fn create_new_tab(size: Size, default_mode: ModeInfo) -> Tab {
|
||||
set_session_name("test".into());
|
||||
let index = 0;
|
||||
let position = 0;
|
||||
@ -108,7 +108,7 @@ fn create_new_tab(size: Size) -> Tab {
|
||||
});
|
||||
let senders = ThreadSenders::default().silently_fail_on_send();
|
||||
let max_panes = None;
|
||||
let mode_info = ModeInfo::default();
|
||||
let mode_info = default_mode;
|
||||
let style = Style::default();
|
||||
let draw_pane_frames = true;
|
||||
let client_id = 1;
|
||||
@ -221,7 +221,7 @@ fn read_fixture(fixture_name: &str) -> Vec<u8> {
|
||||
|
||||
use crate::panes::grid::Grid;
|
||||
use crate::panes::link_handler::LinkHandler;
|
||||
use ::insta::assert_snapshot;
|
||||
use insta::assert_snapshot;
|
||||
use zellij_utils::vte;
|
||||
|
||||
fn take_snapshot(ansi_instructions: &str, rows: usize, columns: usize, palette: Palette) -> String {
|
||||
@ -307,7 +307,7 @@ fn dump_screen() {
|
||||
rows: 20,
|
||||
};
|
||||
let client_id = 1;
|
||||
let mut tab = create_new_tab(size);
|
||||
let mut tab = create_new_tab(size, ModeInfo::default());
|
||||
let map = Arc::new(Mutex::new(HashMap::new()));
|
||||
tab.os_api = Box::new(FakeInputOutput {
|
||||
file_dumps: map.clone(),
|
||||
@ -331,7 +331,7 @@ fn new_floating_pane() {
|
||||
rows: 20,
|
||||
};
|
||||
let client_id = 1;
|
||||
let mut tab = create_new_tab(size);
|
||||
let mut tab = create_new_tab(size, ModeInfo::default());
|
||||
let new_pane_id = PaneId::Terminal(2);
|
||||
let mut output = Output::default();
|
||||
tab.toggle_floating_panes(client_id, None);
|
||||
@ -357,7 +357,7 @@ fn floating_panes_persist_across_toggles() {
|
||||
rows: 20,
|
||||
};
|
||||
let client_id = 1;
|
||||
let mut tab = create_new_tab(size);
|
||||
let mut tab = create_new_tab(size, ModeInfo::default());
|
||||
let new_pane_id = PaneId::Terminal(2);
|
||||
let mut output = Output::default();
|
||||
tab.toggle_floating_panes(client_id, None);
|
||||
@ -387,7 +387,7 @@ fn toggle_floating_panes_off() {
|
||||
rows: 20,
|
||||
};
|
||||
let client_id = 1;
|
||||
let mut tab = create_new_tab(size);
|
||||
let mut tab = create_new_tab(size, ModeInfo::default());
|
||||
let new_pane_id = PaneId::Terminal(2);
|
||||
let mut output = Output::default();
|
||||
tab.toggle_floating_panes(client_id, None);
|
||||
@ -414,7 +414,7 @@ fn toggle_floating_panes_on() {
|
||||
rows: 20,
|
||||
};
|
||||
let client_id = 1;
|
||||
let mut tab = create_new_tab(size);
|
||||
let mut tab = create_new_tab(size, ModeInfo::default());
|
||||
let new_pane_id = PaneId::Terminal(2);
|
||||
let mut output = Output::default();
|
||||
tab.toggle_floating_panes(client_id, None);
|
||||
@ -442,7 +442,7 @@ fn five_new_floating_panes() {
|
||||
rows: 20,
|
||||
};
|
||||
let client_id = 1;
|
||||
let mut tab = create_new_tab(size);
|
||||
let mut tab = create_new_tab(size, ModeInfo::default());
|
||||
let new_pane_id_1 = PaneId::Terminal(2);
|
||||
let new_pane_id_2 = PaneId::Terminal(3);
|
||||
let new_pane_id_3 = PaneId::Terminal(4);
|
||||
@ -480,7 +480,7 @@ fn increase_floating_pane_size() {
|
||||
rows: 20,
|
||||
};
|
||||
let client_id = 1;
|
||||
let mut tab = create_new_tab(size);
|
||||
let mut tab = create_new_tab(size, ModeInfo::default());
|
||||
let new_pane_id_1 = PaneId::Terminal(2);
|
||||
let mut output = Output::default();
|
||||
tab.toggle_floating_panes(client_id, None);
|
||||
@ -507,7 +507,7 @@ fn decrease_floating_pane_size() {
|
||||
rows: 20,
|
||||
};
|
||||
let client_id = 1;
|
||||
let mut tab = create_new_tab(size);
|
||||
let mut tab = create_new_tab(size, ModeInfo::default());
|
||||
let new_pane_id_1 = PaneId::Terminal(2);
|
||||
let mut output = Output::default();
|
||||
tab.toggle_floating_panes(client_id, None);
|
||||
@ -534,7 +534,7 @@ fn resize_floating_pane_left() {
|
||||
rows: 20,
|
||||
};
|
||||
let client_id = 1;
|
||||
let mut tab = create_new_tab(size);
|
||||
let mut tab = create_new_tab(size, ModeInfo::default());
|
||||
let new_pane_id_1 = PaneId::Terminal(2);
|
||||
let mut output = Output::default();
|
||||
tab.toggle_floating_panes(client_id, None);
|
||||
@ -561,7 +561,7 @@ fn resize_floating_pane_right() {
|
||||
rows: 20,
|
||||
};
|
||||
let client_id = 1;
|
||||
let mut tab = create_new_tab(size);
|
||||
let mut tab = create_new_tab(size, ModeInfo::default());
|
||||
let new_pane_id_1 = PaneId::Terminal(2);
|
||||
let mut output = Output::default();
|
||||
tab.toggle_floating_panes(client_id, None);
|
||||
@ -588,7 +588,7 @@ fn resize_floating_pane_up() {
|
||||
rows: 20,
|
||||
};
|
||||
let client_id = 1;
|
||||
let mut tab = create_new_tab(size);
|
||||
let mut tab = create_new_tab(size, ModeInfo::default());
|
||||
let new_pane_id_1 = PaneId::Terminal(2);
|
||||
let mut output = Output::default();
|
||||
tab.toggle_floating_panes(client_id, None);
|
||||
@ -615,7 +615,7 @@ fn resize_floating_pane_down() {
|
||||
rows: 20,
|
||||
};
|
||||
let client_id = 1;
|
||||
let mut tab = create_new_tab(size);
|
||||
let mut tab = create_new_tab(size, ModeInfo::default());
|
||||
let new_pane_id_1 = PaneId::Terminal(2);
|
||||
let mut output = Output::default();
|
||||
tab.toggle_floating_panes(client_id, None);
|
||||
@ -642,7 +642,7 @@ fn move_floating_pane_focus_left() {
|
||||
rows: 20,
|
||||
};
|
||||
let client_id = 1;
|
||||
let mut tab = create_new_tab(size);
|
||||
let mut tab = create_new_tab(size, ModeInfo::default());
|
||||
let new_pane_id_1 = PaneId::Terminal(2);
|
||||
let new_pane_id_2 = PaneId::Terminal(3);
|
||||
let new_pane_id_3 = PaneId::Terminal(4);
|
||||
@ -687,7 +687,7 @@ fn move_floating_pane_focus_right() {
|
||||
rows: 20,
|
||||
};
|
||||
let client_id = 1;
|
||||
let mut tab = create_new_tab(size);
|
||||
let mut tab = create_new_tab(size, ModeInfo::default());
|
||||
let new_pane_id_1 = PaneId::Terminal(2);
|
||||
let new_pane_id_2 = PaneId::Terminal(3);
|
||||
let new_pane_id_3 = PaneId::Terminal(4);
|
||||
@ -733,7 +733,7 @@ fn move_floating_pane_focus_up() {
|
||||
rows: 20,
|
||||
};
|
||||
let client_id = 1;
|
||||
let mut tab = create_new_tab(size);
|
||||
let mut tab = create_new_tab(size, ModeInfo::default());
|
||||
let new_pane_id_1 = PaneId::Terminal(2);
|
||||
let new_pane_id_2 = PaneId::Terminal(3);
|
||||
let new_pane_id_3 = PaneId::Terminal(4);
|
||||
@ -778,7 +778,7 @@ fn move_floating_pane_focus_down() {
|
||||
rows: 20,
|
||||
};
|
||||
let client_id = 1;
|
||||
let mut tab = create_new_tab(size);
|
||||
let mut tab = create_new_tab(size, ModeInfo::default());
|
||||
let new_pane_id_1 = PaneId::Terminal(2);
|
||||
let new_pane_id_2 = PaneId::Terminal(3);
|
||||
let new_pane_id_3 = PaneId::Terminal(4);
|
||||
@ -824,7 +824,7 @@ fn move_floating_pane_focus_with_mouse() {
|
||||
rows: 20,
|
||||
};
|
||||
let client_id = 1;
|
||||
let mut tab = create_new_tab(size);
|
||||
let mut tab = create_new_tab(size, ModeInfo::default());
|
||||
let new_pane_id_1 = PaneId::Terminal(2);
|
||||
let new_pane_id_2 = PaneId::Terminal(3);
|
||||
let new_pane_id_3 = PaneId::Terminal(4);
|
||||
@ -870,7 +870,7 @@ fn move_pane_focus_with_mouse_to_non_floating_pane() {
|
||||
rows: 20,
|
||||
};
|
||||
let client_id = 1;
|
||||
let mut tab = create_new_tab(size);
|
||||
let mut tab = create_new_tab(size, ModeInfo::default());
|
||||
let new_pane_id_1 = PaneId::Terminal(2);
|
||||
let new_pane_id_2 = PaneId::Terminal(3);
|
||||
let new_pane_id_3 = PaneId::Terminal(4);
|
||||
@ -916,7 +916,7 @@ fn drag_pane_with_mouse() {
|
||||
rows: 20,
|
||||
};
|
||||
let client_id = 1;
|
||||
let mut tab = create_new_tab(size);
|
||||
let mut tab = create_new_tab(size, ModeInfo::default());
|
||||
let new_pane_id_1 = PaneId::Terminal(2);
|
||||
let new_pane_id_2 = PaneId::Terminal(3);
|
||||
let new_pane_id_3 = PaneId::Terminal(4);
|
||||
@ -962,7 +962,7 @@ fn mark_text_inside_floating_pane() {
|
||||
rows: 20,
|
||||
};
|
||||
let client_id = 1;
|
||||
let mut tab = create_new_tab(size);
|
||||
let mut tab = create_new_tab(size, ModeInfo::default());
|
||||
let new_pane_id_1 = PaneId::Terminal(2);
|
||||
let new_pane_id_2 = PaneId::Terminal(3);
|
||||
let new_pane_id_3 = PaneId::Terminal(4);
|
||||
@ -1016,7 +1016,7 @@ fn resize_tab_with_floating_panes() {
|
||||
rows: 20,
|
||||
};
|
||||
let client_id = 1;
|
||||
let mut tab = create_new_tab(size);
|
||||
let mut tab = create_new_tab(size, ModeInfo::default());
|
||||
let new_pane_id_1 = PaneId::Terminal(2);
|
||||
let new_pane_id_2 = PaneId::Terminal(3);
|
||||
let new_pane_id_3 = PaneId::Terminal(4);
|
||||
@ -1059,7 +1059,7 @@ fn shrink_whole_tab_with_floating_panes_horizontally_and_vertically() {
|
||||
rows: 20,
|
||||
};
|
||||
let client_id = 1;
|
||||
let mut tab = create_new_tab(size);
|
||||
let mut tab = create_new_tab(size, ModeInfo::default());
|
||||
let new_pane_id_1 = PaneId::Terminal(2);
|
||||
let new_pane_id_2 = PaneId::Terminal(3);
|
||||
let new_pane_id_3 = PaneId::Terminal(4);
|
||||
@ -1099,7 +1099,7 @@ fn shrink_whole_tab_with_floating_panes_horizontally_and_vertically_and_expand_b
|
||||
rows: 20,
|
||||
};
|
||||
let client_id = 1;
|
||||
let mut tab = create_new_tab(size);
|
||||
let mut tab = create_new_tab(size, ModeInfo::default());
|
||||
let new_pane_id_1 = PaneId::Terminal(2);
|
||||
let new_pane_id_2 = PaneId::Terminal(3);
|
||||
let new_pane_id_3 = PaneId::Terminal(4);
|
||||
@ -1143,7 +1143,7 @@ fn embed_floating_pane() {
|
||||
rows: 20,
|
||||
};
|
||||
let client_id = 1;
|
||||
let mut tab = create_new_tab(size);
|
||||
let mut tab = create_new_tab(size, ModeInfo::default());
|
||||
let new_pane_id = PaneId::Terminal(2);
|
||||
let mut output = Output::default();
|
||||
tab.toggle_floating_panes(client_id, None);
|
||||
@ -1170,7 +1170,7 @@ fn float_embedded_pane() {
|
||||
rows: 20,
|
||||
};
|
||||
let client_id = 1;
|
||||
let mut tab = create_new_tab(size);
|
||||
let mut tab = create_new_tab(size, ModeInfo::default());
|
||||
let new_pane_id = PaneId::Terminal(2);
|
||||
let mut output = Output::default();
|
||||
tab.new_pane(new_pane_id, Some(client_id));
|
||||
@ -1196,7 +1196,7 @@ fn cannot_float_only_embedded_pane() {
|
||||
rows: 20,
|
||||
};
|
||||
let client_id = 1;
|
||||
let mut tab = create_new_tab(size);
|
||||
let mut tab = create_new_tab(size, ModeInfo::default());
|
||||
let mut output = Output::default();
|
||||
tab.handle_pty_bytes(
|
||||
1,
|
||||
@ -1223,7 +1223,7 @@ fn replacing_existing_wide_characters() {
|
||||
rows: 48,
|
||||
};
|
||||
let client_id = 1;
|
||||
let mut tab = create_new_tab(size);
|
||||
let mut tab = create_new_tab(size, ModeInfo::default());
|
||||
let mut output = Output::default();
|
||||
let pane_content = read_fixture("ncmpcpp-wide-chars");
|
||||
tab.handle_pty_bytes(1, pane_content);
|
||||
@ -1244,7 +1244,7 @@ fn rename_embedded_pane() {
|
||||
rows: 20,
|
||||
};
|
||||
let client_id = 1;
|
||||
let mut tab = create_new_tab(size);
|
||||
let mut tab = create_new_tab(size, ModeInfo::default());
|
||||
let mut output = Output::default();
|
||||
tab.handle_pty_bytes(
|
||||
1,
|
||||
@ -1268,7 +1268,7 @@ fn rename_floating_pane() {
|
||||
rows: 20,
|
||||
};
|
||||
let client_id = 1;
|
||||
let mut tab = create_new_tab(size);
|
||||
let mut tab = create_new_tab(size, ModeInfo::default());
|
||||
let new_pane_id = PaneId::Terminal(2);
|
||||
let mut output = Output::default();
|
||||
tab.new_pane(new_pane_id, Some(client_id));
|
||||
@ -1296,7 +1296,7 @@ fn wide_characters_in_left_title_side() {
|
||||
rows: 48,
|
||||
};
|
||||
let client_id = 1;
|
||||
let mut tab = create_new_tab(size);
|
||||
let mut tab = create_new_tab(size, ModeInfo::default());
|
||||
let mut output = Output::default();
|
||||
let pane_content = read_fixture("title-wide-chars");
|
||||
tab.handle_pty_bytes(1, pane_content);
|
||||
@ -1316,7 +1316,7 @@ fn save_cursor_position_across_resizes() {
|
||||
// resize the pane
|
||||
let size = Size { cols: 100, rows: 5 };
|
||||
let client_id = 1;
|
||||
let mut tab = create_new_tab(size);
|
||||
let mut tab = create_new_tab(size, ModeInfo::default());
|
||||
let mut output = Output::default();
|
||||
|
||||
tab.handle_pty_bytes(
|
||||
@ -1413,7 +1413,7 @@ fn suppress_tiled_pane() {
|
||||
rows: 20,
|
||||
};
|
||||
let client_id = 1;
|
||||
let mut tab = create_new_tab(size);
|
||||
let mut tab = create_new_tab(size, ModeInfo::default());
|
||||
let new_pane_id = PaneId::Terminal(2);
|
||||
let mut output = Output::default();
|
||||
tab.suppress_active_pane(new_pane_id, client_id);
|
||||
@ -1435,7 +1435,7 @@ fn suppress_floating_pane() {
|
||||
rows: 20,
|
||||
};
|
||||
let client_id = 1;
|
||||
let mut tab = create_new_tab(size);
|
||||
let mut tab = create_new_tab(size, ModeInfo::default());
|
||||
let new_pane_id = PaneId::Terminal(2);
|
||||
let editor_pane_id = PaneId::Terminal(3);
|
||||
let mut output = Output::default();
|
||||
@ -1461,7 +1461,7 @@ fn close_suppressing_tiled_pane() {
|
||||
rows: 20,
|
||||
};
|
||||
let client_id = 1;
|
||||
let mut tab = create_new_tab(size);
|
||||
let mut tab = create_new_tab(size, ModeInfo::default());
|
||||
let new_pane_id = PaneId::Terminal(2);
|
||||
let mut output = Output::default();
|
||||
tab.suppress_active_pane(new_pane_id, client_id);
|
||||
@ -1485,7 +1485,7 @@ fn close_suppressing_floating_pane() {
|
||||
rows: 20,
|
||||
};
|
||||
let client_id = 1;
|
||||
let mut tab = create_new_tab(size);
|
||||
let mut tab = create_new_tab(size, ModeInfo::default());
|
||||
let new_pane_id = PaneId::Terminal(2);
|
||||
let editor_pane_id = PaneId::Terminal(3);
|
||||
let mut output = Output::default();
|
||||
@ -1513,7 +1513,7 @@ fn suppress_tiled_pane_float_it_and_close() {
|
||||
rows: 20,
|
||||
};
|
||||
let client_id = 1;
|
||||
let mut tab = create_new_tab(size);
|
||||
let mut tab = create_new_tab(size, ModeInfo::default());
|
||||
let new_pane_id = PaneId::Terminal(2);
|
||||
let mut output = Output::default();
|
||||
tab.suppress_active_pane(new_pane_id, client_id);
|
||||
@ -1538,7 +1538,7 @@ fn suppress_floating_pane_embed_it_and_close_it() {
|
||||
rows: 20,
|
||||
};
|
||||
let client_id = 1;
|
||||
let mut tab = create_new_tab(size);
|
||||
let mut tab = create_new_tab(size, ModeInfo::default());
|
||||
let new_pane_id = PaneId::Terminal(2);
|
||||
let editor_pane_id = PaneId::Terminal(3);
|
||||
let mut output = Output::default();
|
||||
@ -1567,7 +1567,7 @@ fn resize_whole_tab_while_tiled_pane_is_suppressed() {
|
||||
rows: 20,
|
||||
};
|
||||
let client_id = 1;
|
||||
let mut tab = create_new_tab(size);
|
||||
let mut tab = create_new_tab(size, ModeInfo::default());
|
||||
let new_pane_id = PaneId::Terminal(2);
|
||||
let mut output = Output::default();
|
||||
tab.suppress_active_pane(new_pane_id, client_id);
|
||||
@ -1593,7 +1593,7 @@ fn resize_whole_tab_while_floting_pane_is_suppressed() {
|
||||
rows: 20,
|
||||
};
|
||||
let client_id = 1;
|
||||
let mut tab = create_new_tab(size);
|
||||
let mut tab = create_new_tab(size, ModeInfo::default());
|
||||
let new_pane_id = PaneId::Terminal(2);
|
||||
let editor_pane_id = PaneId::Terminal(3);
|
||||
let mut output = Output::default();
|
||||
@ -1615,3 +1615,108 @@ fn resize_whole_tab_while_floting_pane_is_suppressed() {
|
||||
);
|
||||
assert_snapshot!(snapshot);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn enter_search_pane() {
|
||||
let size = Size {
|
||||
cols: 121,
|
||||
rows: 20,
|
||||
};
|
||||
let client_id = 1;
|
||||
let mode_info = ModeInfo {
|
||||
mode: InputMode::Search,
|
||||
..Default::default()
|
||||
};
|
||||
let mut tab = create_new_tab(size, mode_info);
|
||||
let mut output = Output::default();
|
||||
let pane_content = read_fixture("grid_copy");
|
||||
tab.handle_pty_bytes(1, pane_content);
|
||||
tab.render(&mut output, None);
|
||||
let snapshot = take_snapshot(
|
||||
output.serialize().get(&client_id).unwrap(),
|
||||
size.rows,
|
||||
size.cols,
|
||||
Palette::default(),
|
||||
);
|
||||
assert_snapshot!("search_tab_nothing_highlighted", snapshot);
|
||||
|
||||
// Pane title should show 'tortor' as search term
|
||||
// Only lines containing 'tortor' get marked as render-targets, so
|
||||
// only those are updated (search-styling is not visible here).
|
||||
tab.update_search_term("tortor".as_bytes().to_vec(), client_id);
|
||||
tab.render(&mut output, None);
|
||||
let snapshot = take_snapshot(
|
||||
output.serialize().get(&client_id).unwrap(),
|
||||
size.rows,
|
||||
size.cols,
|
||||
Palette::default(),
|
||||
);
|
||||
assert_snapshot!("search_tab_highlight_tortor", snapshot);
|
||||
|
||||
// Pane title should show search modifiers
|
||||
tab.toggle_search_wrap(client_id);
|
||||
tab.toggle_search_whole_words(client_id);
|
||||
tab.toggle_search_case_sensitivity(client_id);
|
||||
tab.render(&mut output, None);
|
||||
let snapshot = take_snapshot(
|
||||
output.serialize().get(&client_id).unwrap(),
|
||||
size.rows,
|
||||
size.cols,
|
||||
Palette::default(),
|
||||
);
|
||||
assert_snapshot!("search_tab_highlight_tortor_modified", snapshot);
|
||||
|
||||
// And only the search term again
|
||||
tab.toggle_search_wrap(client_id);
|
||||
tab.toggle_search_whole_words(client_id);
|
||||
tab.toggle_search_case_sensitivity(client_id);
|
||||
|
||||
tab.render(&mut output, None);
|
||||
let snapshot = take_snapshot(
|
||||
output.serialize().get(&client_id).unwrap(),
|
||||
size.rows,
|
||||
size.cols,
|
||||
Palette::default(),
|
||||
);
|
||||
assert_snapshot!("search_tab_highlight_tortor", snapshot);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn enter_search_floating_pane() {
|
||||
let size = Size {
|
||||
cols: 121,
|
||||
rows: 20,
|
||||
};
|
||||
let client_id = 1;
|
||||
let mode_info = ModeInfo {
|
||||
mode: InputMode::Search,
|
||||
..Default::default()
|
||||
};
|
||||
let mut tab = create_new_tab(size, mode_info);
|
||||
let new_pane_id = PaneId::Terminal(2);
|
||||
let mut output = Output::default();
|
||||
tab.toggle_floating_panes(client_id, None);
|
||||
tab.new_pane(new_pane_id, Some(client_id));
|
||||
|
||||
let pane_content = read_fixture("grid_copy");
|
||||
tab.handle_pty_bytes(2, pane_content);
|
||||
tab.render(&mut output, None);
|
||||
let snapshot = take_snapshot(
|
||||
output.serialize().get(&client_id).unwrap(),
|
||||
size.rows,
|
||||
size.cols,
|
||||
Palette::default(),
|
||||
);
|
||||
assert_snapshot!("search_floating_tab_nothing_highlighted", snapshot);
|
||||
|
||||
// Only the line inside the floating tab which contain 'fring' should be in the new snapshot
|
||||
tab.update_search_term("fring".as_bytes().to_vec(), client_id);
|
||||
tab.render(&mut output, None);
|
||||
let snapshot = take_snapshot(
|
||||
output.serialize().get(&client_id).unwrap(),
|
||||
size.rows,
|
||||
size.cols,
|
||||
Palette::default(),
|
||||
);
|
||||
assert_snapshot!("search_floating_tab_highlight_fring", snapshot);
|
||||
}
|
||||
|
@ -324,6 +324,90 @@ keybinds:
|
||||
# uncomment this and adjust key if using copy_on_select=false
|
||||
# - action: [Copy: ]
|
||||
# key: [ Alt: 'c']
|
||||
- action: [SwitchToMode: EnterSearch, SearchInput: [0],]
|
||||
key: [Char: 's']
|
||||
entersearch:
|
||||
- action: [SwitchToMode: Search,]
|
||||
key: [Char: "\n"]
|
||||
- action: [SearchInput: [27], SwitchToMode: Scroll,]
|
||||
key: [Ctrl: 'c', Esc]
|
||||
- action: [NewPane: ,]
|
||||
key: [ Alt: 'n',]
|
||||
- action: [MoveFocusOrTab: Left,]
|
||||
key: [ Alt: 'h', Alt: Left]
|
||||
- action: [MoveFocusOrTab: Right,]
|
||||
key: [ Alt: 'l', Alt: Right]
|
||||
- action: [MoveFocus: Down,]
|
||||
key: [ Alt: 'j', Alt: Down]
|
||||
- action: [MoveFocus: Up,]
|
||||
key: [ Alt: 'k', Alt: Up]
|
||||
- action: [Resize: Increase,]
|
||||
key: [ Alt: '=']
|
||||
- action: [Resize: Increase,]
|
||||
key: [ Alt: '+']
|
||||
- action: [Resize: Decrease,]
|
||||
key: [ Alt: '-']
|
||||
search:
|
||||
- action: [SwitchToMode: Normal,]
|
||||
key: [Ctrl: 's', Char: ' ', Char: "\n", Esc]
|
||||
- action: [SwitchToMode: Tab,]
|
||||
key: [Ctrl: 't',]
|
||||
- action: [SwitchToMode: Locked,]
|
||||
key: [Ctrl: 'g',]
|
||||
- action: [SwitchToMode: Pane,]
|
||||
key: [Ctrl: 'p',]
|
||||
- action: [SwitchToMode: Move,]
|
||||
key: [Ctrl: 'h',]
|
||||
- action: [SwitchToMode: Tmux,]
|
||||
key: [Ctrl: 'b',]
|
||||
- action: [SwitchToMode: Session,]
|
||||
key: [Ctrl: 'o',]
|
||||
- action: [SwitchToMode: Resize,]
|
||||
key: [Ctrl: 'n',]
|
||||
- action: [ScrollToBottom, SwitchToMode: Normal,]
|
||||
key: [Ctrl: 'c',]
|
||||
- action: [Quit,]
|
||||
key: [Ctrl: 'q',]
|
||||
- action: [ScrollDown,]
|
||||
key: [Char: 'j', Down,]
|
||||
- action: [ScrollUp,]
|
||||
key: [Char: 'k', Up,]
|
||||
- action: [PageScrollDown,]
|
||||
key: [Ctrl: 'f', PageDown, Right, Char: 'l',]
|
||||
- action: [PageScrollUp,]
|
||||
key: [Ctrl: 'b', PageUp, Left, Char: 'h',]
|
||||
- action: [HalfPageScrollDown,]
|
||||
key: [Char: 'd',]
|
||||
- action: [HalfPageScrollUp,]
|
||||
key: [Char: 'u',]
|
||||
- action: [NewPane: ,]
|
||||
key: [ Alt: 'n',]
|
||||
- action: [MoveFocusOrTab: Left,]
|
||||
key: [ Alt: 'h', Alt: Left] # The Alt: Left etc. variants are temporary hacks and will be removed in the future - please do not rely on them!
|
||||
- action: [MoveFocusOrTab: Right,]
|
||||
key: [ Alt: 'l', Alt: Right]
|
||||
- action: [MoveFocus: Down,]
|
||||
key: [ Alt: 'j', Alt: Down]
|
||||
- action: [MoveFocus: Up,]
|
||||
key: [ Alt: 'k', Alt: Up]
|
||||
- action: [Resize: Increase,]
|
||||
key: [ Alt: '=']
|
||||
- action: [Resize: Increase,]
|
||||
key: [ Alt: '+']
|
||||
- action: [Resize: Decrease,]
|
||||
key: [ Alt: '-']
|
||||
- action: [SwitchToMode: EnterSearch, SearchInput: [0],]
|
||||
key: [Char: 's']
|
||||
- action: [Search: Down]
|
||||
key: [Char: 'n']
|
||||
- action: [Search: Up]
|
||||
key: [Char: 'p']
|
||||
- action: [SearchToggleOption: CaseSensitivity]
|
||||
key: [Char: 'c']
|
||||
- action: [SearchToggleOption: Wrap]
|
||||
key: [Char: 'w']
|
||||
- action: [SearchToggleOption: WholeWord]
|
||||
key: [Char: 'o']
|
||||
renametab:
|
||||
- action: [SwitchToMode: Normal,]
|
||||
key: [Char: "\n", Ctrl: 'c', Esc]
|
||||
|
@ -120,6 +120,12 @@ pub enum InputMode {
|
||||
/// `Scroll` mode allows scrolling up and down within a pane.
|
||||
#[serde(alias = "scroll")]
|
||||
Scroll,
|
||||
/// `EnterSearch` mode allows for typing in the needle for a search in the scroll buffer of a pane.
|
||||
#[serde(alias = "entersearch")]
|
||||
EnterSearch,
|
||||
/// `Search` mode allows for searching a term in a pane (superset of `Scroll`).
|
||||
#[serde(alias = "search")]
|
||||
Search,
|
||||
/// `RenameTab` mode allows assigning a new name to a tab.
|
||||
#[serde(alias = "renametab")]
|
||||
RenameTab,
|
||||
@ -179,6 +185,8 @@ impl FromStr for InputMode {
|
||||
"pane" => Ok(InputMode::Pane),
|
||||
"tab" => Ok(InputMode::Tab),
|
||||
"scroll" => Ok(InputMode::Scroll),
|
||||
"search" => Ok(InputMode::Search),
|
||||
"entersearch" => Ok(InputMode::EnterSearch),
|
||||
"renametab" => Ok(InputMode::RenameTab),
|
||||
"session" => Ok(InputMode::Session),
|
||||
"move" => Ok(InputMode::Move),
|
||||
|
@ -291,6 +291,12 @@ pub enum ScreenContext {
|
||||
RemoveOverlay,
|
||||
ConfirmPrompt,
|
||||
DenyPrompt,
|
||||
UpdateSearch,
|
||||
SearchDown,
|
||||
SearchUp,
|
||||
SearchToggleCaseSensitivity,
|
||||
SearchToggleWholeWord,
|
||||
SearchToggleWrap,
|
||||
}
|
||||
|
||||
/// Stack call representations corresponding to the different types of [`PtyInstruction`]s.
|
||||
|
@ -27,6 +27,19 @@ pub enum ResizeDirection {
|
||||
Decrease,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Deserialize, Serialize)]
|
||||
pub enum SearchDirection {
|
||||
Down,
|
||||
Up,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
|
||||
pub enum SearchOption {
|
||||
CaseSensitivity,
|
||||
WholeWord,
|
||||
Wrap,
|
||||
}
|
||||
|
||||
// As these actions are bound to the default config, please
|
||||
// do take care when refactoring - or renaming.
|
||||
// They might need to be adjusted in the default config
|
||||
@ -121,6 +134,12 @@ pub enum Action {
|
||||
Deny,
|
||||
/// Confirm an action that invokes a prompt automatically
|
||||
SkipConfirm(Box<Action>),
|
||||
/// Search for String
|
||||
SearchInput(Vec<u8>),
|
||||
/// Search for something
|
||||
Search(SearchDirection),
|
||||
/// Toggle case sensitivity of search
|
||||
SearchToggleOption(SearchOption),
|
||||
}
|
||||
|
||||
impl From<OnForceClose> for Action {
|
||||
|
@ -213,6 +213,7 @@ impl Keybinds {
|
||||
},
|
||||
InputMode::RenameTab => mode_keybind_or_action(Action::TabNameInput(raw_bytes)),
|
||||
InputMode::RenamePane => mode_keybind_or_action(Action::PaneNameInput(raw_bytes)),
|
||||
InputMode::EnterSearch => mode_keybind_or_action(Action::SearchInput(raw_bytes)),
|
||||
_ => mode_keybind_or_action(Action::NoOp),
|
||||
}
|
||||
}
|
||||
|
@ -59,6 +59,18 @@ pub fn get_mode_info(mode: InputMode, style: Style, capabilities: PluginCapabili
|
||||
"e".to_string(),
|
||||
"Edit Scrollback in Default Editor".to_string(),
|
||||
),
|
||||
("s".to_string(), "Enter search term".to_string()),
|
||||
],
|
||||
InputMode::EnterSearch => vec![("Enter".to_string(), "when done".to_string())],
|
||||
InputMode::Search => vec![
|
||||
("↓↑".to_string(), "Scroll".to_string()),
|
||||
("PgUp/PgDn".to_string(), "Scroll Page".to_string()),
|
||||
("u/d".to_string(), "Scroll Half Page".to_string()),
|
||||
("n".to_string(), "Search down".to_string()),
|
||||
("p".to_string(), "Search up".to_string()),
|
||||
("c".to_string(), "Case sensitivity".to_string()),
|
||||
("w".to_string(), "Wrap".to_string()),
|
||||
("o".to_string(), "Whole words".to_string()),
|
||||
],
|
||||
InputMode::RenameTab => vec![("Enter".to_string(), "when done".to_string())],
|
||||
InputMode::RenamePane => vec![("Enter".to_string(), "when done".to_string())],
|
||||
|
Loading…
Reference in New Issue
Block a user