[
  {
    "path": ".cargo/config.toml",
    "content": "[build]\ntarget = \"wasm32-wasi\"\n"
  },
  {
    "path": ".gitignore",
    "content": "/target\n"
  },
  {
    "path": "Cargo.toml",
    "content": "[package]\nname = \"zellij_forgot\"\nversion = \"0.4.2\"\nedition = \"2021\"\nauthors = [\"Karim Ould Mahieddine\"]\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nowo-colors = \"4.1.0\"\nzellij-tile = \"0.41.2\"\nchrono = \"0.4\"\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2026 Karim Ould Mahieddine\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# ❔Zellij Forgot\n\nZellij is your solution for quickly accessing and remembering your keybindings (or anything else) in Zellij.\nForget the hassle of remembering all your keybindings (or other stuff), let Zellij Forgot do it for you!\n\n![usage](https://github.com/karimould/zellij-forgot/raw/main/assets/forgot.gif)\n\n## 🛠️ Installation\n\nTo install the Zellij Forgot plugin, follow the standard plugin installation process for Zellij.\nPlace the compiled zellij_forgot.wasm file in the appropriate directory.\nYou can find the current release [here](https://github.com/karimould/zellij-forgot/releases)\n\n1. Download the `zellij_forgot.wasm` file from the release matching your installed Zellij version\n2. Place it in `~/zellij-plugins`\n3. From inside Zellij, run `zellij action new-pane --plugin file:~/zellij-plugins/zellij_forgot.wasm --floating`\n\n## 🎹 Set Up Your Keybinds and Activate 'Zellij Forgot' with Ease\n\nThe 'Zellij Forgot' plugin fetches the displayed keybinds—or anything else you want to remember—directly\nfrom the plugin's configuration key-value map, or automatically loads them from your Zellij keybinds.\n\nHowever, if you prefer not to automatically load the Zellij keybindings,\nyou can easily opt out of this feature.\nTo disable automatic keybinding loading, simply add the following line to your plugin configuration:\n\n```kdl\n\n            \"LOAD_ZELLIJ_BINDINGS\" \"false\"\n\n```\n\nHere is an example with some stuff to remember/forget.\n\n```kdl\nshared_except \"locked\" {\n    bind \"Ctrl y\" {\n        LaunchOrFocusPlugin \"file:~/zellij-plugins/zellij_forgot.wasm\" {\n            \"LOAD_ZELLIJ_BINDINGS\" \"false\"\n            \"buy eggs\" \"5x\"\n            \"learn rust\" \"5h\"\n            \"clean up code\" \"tomorrow\"\n            floating true\n        }\n    }\n}\n```\n\nBelow is an example using Zellij's default keybinds.\nTo integrate this into your setup, append the following snippet to your zellij config, specifically within the keybinds segment:\n\nAdd the following to your [zellij config](https://zellij.dev/documentation/configuration.html) somewhere inside the [`keybinds`](https://zellij.dev/documentation/keybindings.html) section:\n\n```kdl\nshared_except \"locked\" {\n    bind \"Ctrl y\" {\n        LaunchOrFocusPlugin \"file:~/zellij-plugins/zellij_forgot.wasm\" {\n            \"lock\"                  \"ctrl + g\"\n            \"unlock\"                \"ctrl + g\"\n            \"new pane\"              \"ctrl + p + n\"\n            \"change focus of pane\"  \"ctrl + p + arrow key\"\n            \"close pane\"            \"ctrl + p + x\"\n            \"rename pane\"           \"ctrl + p + c\"\n            \"toggle fullscreen\"     \"ctrl + p + f\"\n            \"toggle floating pane\"  \"ctrl + p + w\"\n            \"toggle embed pane\"     \"ctrl + p + e\"\n            \"choose right pane\"     \"ctrl + p + l\"\n            \"choose left pane\"      \"ctrl + p + r\"\n            \"choose upper pane\"     \"ctrl + p + k\"\n            \"choose lower pane\"     \"ctrl + p + j\"\n            \"new tab\"               \"ctrl + t + n\"\n            \"close tab\"             \"ctrl + t + x\"\n            \"change focus of tab\"   \"ctrl + t + arrow key\"\n            \"rename tab\"            \"ctrl + t + r\"\n            \"sync tab\"              \"ctrl + t + s\"\n            \"brake pane to new tab\" \"ctrl + t + b\"\n            \"brake pane left\"       \"ctrl + t + [\"\n            \"brake pane right\"      \"ctrl + t + ]\"\n            \"toggle tab\"            \"ctrl + t + tab\"\n            \"increase pane size\"    \"ctrl + n + +\"\n            \"decrease pane size\"    \"ctrl + n + -\"\n            \"increase pane top\"     \"ctrl + n + k\"\n            \"increase pane right\"   \"ctrl + n + l\"\n            \"increase pane bottom\"  \"ctrl + n + j\"\n            \"increase pane left\"    \"ctrl + n + h\"\n            \"decrease pane top\"     \"ctrl + n + K\"\n            \"decrease pane right\"   \"ctrl + n + L\"\n            \"decrease pane bottom\"  \"ctrl + n + J\"\n            \"decrease pane left\"    \"ctrl + n + H\"\n            \"move pane to top\"      \"ctrl + h + k\"\n            \"move pane to right\"    \"ctrl + h + l\"\n            \"move pane to bottom\"   \"ctrl + h + j\"\n            \"move pane to left\"     \"ctrl + h + h\"\n            \"search\"                \"ctrl + s + s\"\n            \"go into edit mode\"     \"ctrl + s + e\"\n            \"detach session\"        \"ctrl + o + w\"\n            \"open session manager\"  \"ctrl + o + w\"\n            \"quit zellij\"           \"ctrl + q\"\n            floating true\n        }\n    }\n}\n```\n\nRemember, this is just a template. Feel free to customize the keybindings to better suit your workflow!\n\n## Development\n\nLoad the `dev.kdl` layout from inside zellij: `zellij action new-tab -l dev.kdl` or from outside Zellij with `zellij -l dev.kdl`\n"
  },
  {
    "path": "dev.kdl",
    "content": "layout {\n    pane size=1 borderless=true {\n        plugin location=\"zellij:tab-bar\"\n    }\n    pane split_direction=\"vertical\" {\n        pane command=\"nvim\"\n        pane {\n            pane edit=\"Cargo.toml\"\n            pane stacked=true {\n                pane size=\"10%\" command=\"bash\" name=\"COMPILE AND RELOAD PLUGIN\" {\n                    args \"-c\" \"cargo build && zellij action start-or-reload-plugin file:target/wasm32-wasi/debug/zellij_forgot.wasm\"\n                    // if you have \"watchexec\" installed, you can comment the above line and uncomment the below one to build + reload the plugin on fs changes\n                    // args \"-c\" \"watchexec 'cargo build && zellij action start-or-reload-plugin file:target/wasm32-wasi/debug/rust-plugin-example.wasm'\"\n                }\n                pane name=\"zellij_forgot\" {\n                    plugin location=\"file:target/wasm32-wasi/debug/zellij_forgot.wasm\" {\n                      \"lock\"                  \"ctrl + g\"\n                      \"unlock\"                \"ctrl + g\"\n                      \"new pane\"              \"ctrl + p + n\"\n                      \"change focus of pane\"  \"ctrl + p + arrow key\"\n                      \"close pane\"            \"ctrl + p + x\"\n                      \"rename pane\"           \"ctrl + p + c\"\n                      \"toggle fullscreen\"     \"ctrl + p + f\"\n                      \"toggle floating pane\"  \"ctrl + p + w\"\n                      \"toggle embed pane\"     \"ctrl + p + e\"\n                      \"choose right pane\"     \"ctrl + p + l\"\n                      \"choose left pane\"      \"ctrl + p + r\"\n                      \"choose upper pane\"     \"ctrl + p + k\"\n                      \"choose lower pane\"     \"ctrl + p + j\"\n                      \"new tab\"               \"ctrl + t + n\"\n                      \"close tab\"             \"ctrl + t + x\"\n                      \"change focus of tab\"   \"ctrl + t + arrow key\"\n                      \"rename tab\"            \"ctrl + t + r\"\n                      \"sync tab\"              \"ctrl + t + s\"\n                      \"brake pane to new tab\" \"ctrl + t + b\"\n                      \"brake pane left\"       \"ctrl + t + [\"\n                      \"brake pane right\"      \"ctrl + t + ]\"\n                      \"toggle tab\"            \"ctrl + t + tab\"\n                      \"increase pane size\"    \"ctrl + n + +\"\n                      \"decrease pane size\"    \"ctrl + n + -\"\n                      \"increase pane top\"     \"ctrl + n + k\"\n                      \"increase pane right\"   \"ctrl + n + l\"\n                      \"increase pane bottom\"  \"ctrl + n + j\"\n                      \"increase pane left\"    \"ctrl + n + h\"\n                      \"decrease pane top\"     \"ctrl + n + K\"\n                      \"decrease pane right\"   \"ctrl + n + L\"\n                      \"decrease pane bottom\"  \"ctrl + n + J\"\n                      \"decrease pane left\"    \"ctrl + n + H\"\n                      \"move pane to top\"      \"ctrl + h + k\"\n                      \"move pane to right\"    \"ctrl + h + l\"\n                      \"move pane to bottom\"   \"ctrl + h + j\"\n                      \"move pane to left\"     \"ctrl + h + h\"\n                      \"search\"                \"ctrl + s + s\"\n                      \"go into edit mode\"     \"ctrl + s + e\"\n                      \"detach session\"        \"ctrl + o + w\"\n                      \"open session manager\"  \"ctrl + o + w\"\n                      \"quit zellij\"           \"ctrl + q\"\n\n                   }\n                }\n            }\n        }\n    }\n    pane size=2 borderless=true {\n        plugin location=\"zellij:status-bar\"\n    }\n}\n"
  },
  {
    "path": "src/helper.rs",
    "content": "use zellij_tile::prelude::{actions::Action, InputMode};\n\npub fn modes_to_string(mode: InputMode) -> String {\n    match mode {\n        InputMode::Normal => \"Normal\".to_string(),\n        InputMode::Locked => \"Locked\".to_string(),\n        InputMode::Resize => \"Resize\".to_string(),\n        InputMode::Pane => \"Pane\".to_string(),\n        InputMode::Tab => \"Tab\".to_string(),\n        InputMode::Scroll => \"Scroll\".to_string(),\n        InputMode::EnterSearch => \"Enter Search\".to_string(),\n        InputMode::Search => \"Search\".to_string(),\n        InputMode::RenameTab => \"RenameTab\".to_string(),\n        InputMode::RenamePane => \"RenamePane\".to_string(),\n        InputMode::Session => \"Session\".to_string(),\n        InputMode::Move => \"Move\".to_string(),\n        InputMode::Prompt => \"Prompt\".to_string(),\n        InputMode::Tmux => \"Tmux\".to_string(),\n    }\n}\n\n//  Zellij Version 0.41.2\npub fn actions_to_string(actions: Vec<Action>) -> String {\n    actions\n        .iter()\n        .map(|action| match action {\n            Action::Quit => \"Quit\".to_string(),\n            Action::Write(key, data, bool) => format!(\n                \"Write({:?}, {}, {})\",\n                key,\n                String::from_utf8_lossy(data),\n                bool\n            ),\n            Action::WriteChars(chars) => format!(\"WriteChars({})\", chars),\n            Action::SwitchToMode(mode) => format!(\"SwitchToMode({:?})\", mode),\n            Action::SwitchModeForAllClients(mode) => format!(\"SwitchModeForAllClients({:?})\", mode),\n            Action::Resize(resize, direction) => format!(\"Resize({:?}, {:?})\", resize, direction),\n            Action::FocusNextPane => \"FocusNextPane\".to_string(),\n            Action::FocusPreviousPane => \"FocusPreviousPane\".to_string(),\n            Action::MoveFocus(direction) => format!(\"MoveFocus({:?})\", direction),\n            Action::MoveFocusOrTab(direction) => format!(\"MoveFocusOrTab({:?})\", direction),\n            Action::MovePane(direction) => format!(\"MovePane({:?})\", direction),\n            Action::MovePaneBackwards => \"MovePaneBackward\".to_string(),\n            Action::ClearScreen => \"ClearScreen\".to_string(),\n            Action::DumpScreen(_, _) => \"DumpScreen\".to_string(),\n            Action::DumpLayout => \"DumpLayout\".to_string(),\n            Action::EditScrollback => \"EditScrollback\".to_string(),\n            Action::ScrollUp => \"ScrollUp\".to_string(),\n            Action::ScrollUpAt(position) => format!(\"ScrollUpAt({:?})\", position),\n            Action::ScrollDown => \"ScrollDown\".to_string(),\n            Action::ScrollDownAt(position) => format!(\"ScrollDownAt({:?})\", position),\n            Action::ScrollToBottom => \"ScrollToBottom\".to_string(),\n            Action::ScrollToTop => \"ScrollToTop\".to_string(),\n            Action::PageScrollUp => \"PageScrollUp\".to_string(),\n            Action::PageScrollDown => \"PageScrollDown\".to_string(),\n            Action::HalfPageScrollUp => \"HalfPageScrollUp\".to_string(),\n            Action::HalfPageScrollDown => \"HalfPageScrollDown\".to_string(),\n            Action::ToggleFocusFullscreen => \"ToggleFocusFullscreen\".to_string(),\n            Action::TogglePaneFrames => \"TogglePaneFrames\".to_string(),\n            Action::ToggleActiveSyncTab => \"ToggleActiveSyncTab\".to_string(),\n            Action::NewPane(direction, command, bool) => {\n                format!(\"NewPane({:?}, {:?}, {})\", direction, command, bool)\n            }\n            Action::EditFile(path, direction, bool1, bool2, bool3, coordinates) => format!(\n                \"EditFile({:?}, {:?}, {}, {}, {}, {:?})\",\n                path, direction, bool1, bool2, bool3, coordinates\n            ),\n            Action::NewFloatingPane(run_command_action, command, option) => {\n                format!(\n                    \"NewFloatingPane({:?}, {:?}, {:?})\",\n                    run_command_action, command, option\n                )\n            }\n            Action::NewTiledPane(direction, run_command_action, command) => format!(\n                \"NewTiledPane({:?}, {:?}, {:?})\",\n                direction, run_command_action, command\n            ),\n            Action::NewInPlacePane(run_command_action, command) => {\n                format!(\"NewInPlacePane({:?}, {:?})\", run_command_action, command)\n            }\n            Action::TogglePaneEmbedOrFloating => \"TogglePaneEmbedOrFloating\".to_string(),\n            Action::ToggleFloatingPanes => \"ToggleFloatingPanes\".to_string(),\n            Action::CloseFocus => \"CloseFocus\".to_string(),\n            Action::PaneNameInput(data) => {\n                format!(\"PaneNameInput({})\", String::from_utf8_lossy(data))\n            }\n            Action::UndoRenamePane => \"UndoRenamePane\".to_string(),\n            Action::NewTab(..) => \"NewTab\".to_string(),\n            Action::NoOp => \"NoOp\".to_string(),\n            Action::GoToNextTab => \"GoToNextTab\".to_string(),\n            Action::GoToPreviousTab => \"GoToPreviousTab\".to_string(),\n            Action::CloseTab => \"CloseTab\".to_string(),\n            Action::GoToTab(index) => format!(\"GoToTab({})\", index),\n            Action::GoToTabName(name, exact) => format!(\"GoToTabName({}, {})\", name, exact),\n            Action::ToggleTab => \"ToggleTab\".to_string(),\n            Action::TabNameInput(data) => {\n                format!(\"TabNameInput({})\", String::from_utf8_lossy(data))\n            }\n            Action::UndoRenameTab => \"UndoRenameTab\".to_string(),\n            Action::Run(run_command_action) => format!(\"Run({:?})\", run_command_action),\n            Action::Detach => \"Detach\".to_string(),\n            Action::LeftClick(position) => format!(\"LeftClick({:?})\", position),\n            Action::RightClick(position) => format!(\"RightClick({:?})\", position),\n            Action::MiddleClick(position) => format!(\"MiddleClick({:?})\", position),\n            Action::LaunchOrFocusPlugin(plugin, _, _, _, _) => {\n                format!(\"LaunchOrFocusPlugin({})\", plugin.location_string())\n            }\n            Action::LaunchPlugin(_, _, _, _, _) => \"LaunchPlugin\".to_string(),\n            Action::LeftMouseRelease(position) => format!(\"LeftMouseRelease({:?})\", position),\n            Action::RightMouseRelease(position) => format!(\"RightMouseRelease({:?})\", position),\n            Action::MiddleMouseRelease(position) => format!(\"MiddleMouseRelease({:?})\", position),\n            Action::MouseHoldLeft(position) => format!(\"MouseHoldLeft({:?})\", position),\n            Action::MouseHoldRight(position) => format!(\"MouseHoldRight({:?})\", position),\n            Action::MouseHoldMiddle(position) => format!(\"MouseHoldMiddle({:?})\", position),\n            Action::Copy => \"Copy\".to_string(),\n            Action::Confirm => \"Confirm\".to_string(),\n            Action::Deny => \"Deny\".to_string(),\n            Action::SkipConfirm(_) => \"SkipConfirm\".to_string(),\n            Action::SearchInput(data) => format!(\"SearchInput({})\", String::from_utf8_lossy(data)),\n            Action::Search(direction) => format!(\"Search({:?})\", direction),\n            Action::SearchToggleOption(option) => format!(\"SearchToggleOption({:?})\", option),\n            Action::ToggleMouseMode => \"ToggleMouseMode\".to_string(),\n            Action::PreviousSwapLayout => \"PreviousSwapLayout\".to_string(),\n            Action::NextSwapLayout => \"NextSwapLayout\".to_string(),\n            Action::QueryTabNames => \"QueryTabNames\".to_string(),\n            Action::NewTiledPluginPane(plugin, _, _, _) => {\n                format!(\"NewTiledPluginPane({})\", plugin.location_string())\n            }\n            Action::NewFloatingPluginPane(plugin, _, _, _, _) => {\n                format!(\"NewFloatingPluginPane({})\", plugin.location_string())\n            }\n            Action::NewInPlacePluginPane(plugin, _, _) => {\n                format!(\"NewInPlacePluginPane({})\", plugin.location_string())\n            }\n            Action::StartOrReloadPlugin(plugin) => {\n                format!(\"StartOrReloadPlugin({})\", plugin.location_string())\n            }\n            Action::CloseTerminalPane(id) => format!(\"CloseTerminalPane({})\", id),\n            Action::ClosePluginPane(id) => format!(\"ClosePluginPane({})\", id),\n            Action::FocusTerminalPaneWithId(id, force) => {\n                format!(\"FocusTerminalPaneWithId({}, {})\", id, force)\n            }\n            Action::FocusPluginPaneWithId(id, force) => {\n                format!(\"FocusPluginPaneWithId({}, {})\", id, force)\n            }\n            Action::RenameTerminalPane(id, data) => format!(\n                \"RenameTerminalPane({}, {})\",\n                id,\n                String::from_utf8_lossy(data)\n            ),\n            Action::RenamePluginPane(id, data) => format!(\n                \"RenamePluginPane({}, {})\",\n                id,\n                String::from_utf8_lossy(data)\n            ),\n            Action::RenameTab(id, data) => {\n                format!(\"RenameTab({}, {})\", id, String::from_utf8_lossy(data))\n            }\n            Action::BreakPane => \"BreakPane\".to_string(),\n            Action::BreakPaneRight => \"BreakPaneRight\".to_string(),\n            Action::BreakPaneLeft => \"BreakPaneLeft\".to_string(),\n            Action::RenameSession(name) => format!(\"RenameSession({})\", name),\n            _ => \"Unknown Action\".to_string(),\n        })\n        .collect::<Vec<String>>()\n        .join(\", \")\n}\n"
  },
  {
    "path": "src/main.rs",
    "content": "use owo_colors::OwoColorize;\nuse std::collections::BTreeMap;\nuse zellij_tile::prelude::*;\nmod helper;\n\nstatic LOAD_ZELLIJ_BINDINGS: &str = \"LOAD_ZELLIJ_BINDINGS\";\n\n#[derive(Default)]\nstruct State {\n    load_zellij_bindings: Option<String>,\n    keybinds: BTreeMap<String, String>,\n    filter: String,\n}\n\nimpl State {\n    fn filtered_keybinds(&self) -> Vec<(&String, &String)> {\n        let filter = self.filter.to_lowercase();\n\n        self.keybinds\n            .iter()\n            .filter(|(k, v)| {\n                k.to_lowercase().contains(&filter) || v.to_lowercase().contains(&filter)\n            })\n            .collect()\n    }\n    fn max_key_length(&self) -> usize {\n        self.filtered_keybinds()\n            .iter()\n            .map(|(key, _)| key.len())\n            .max()\n            .unwrap_or(0)\n    }\n}\n\nregister_plugin!(State);\n\nimpl ZellijPlugin for State {\n    fn load(&mut self, configuration: BTreeMap<String, String>) {\n        request_permission(&[\n            PermissionType::ReadApplicationState,\n            PermissionType::ChangeApplicationState,\n        ]);\n        subscribe(&[EventType::Key, EventType::ModeUpdate]);\n\n        self.load_zellij_bindings = configuration.get(LOAD_ZELLIJ_BINDINGS).cloned();\n        self.keybinds = configuration;\n        self.keybinds.remove(LOAD_ZELLIJ_BINDINGS);\n    }\n\n    fn update(&mut self, event: Event) -> bool {\n        let mut should_render = false;\n        match event {\n            Event::Key(key) => match key.bare_key {\n                BareKey::Esc => {\n                    close_focus();\n                }\n                BareKey::Char('c') if key.has_modifiers(&[KeyModifier::Ctrl]) => {\n                    close_focus();\n                }\n                BareKey::Backspace => {\n                    self.filter.pop();\n                    should_render = true;\n                }\n                BareKey::Char(c)\n                    if c.is_ascii_alphanumeric() || c == '-' || c == ':' || c.is_whitespace() =>\n                {\n                    self.filter.push(c);\n                    should_render = true;\n                }\n                _ => {}\n            },\n            Event::ModeUpdate(mode_info) => {\n                match self.load_zellij_bindings == Some(\"false\".to_string()) {\n                    true => {}\n                    false => {\n                        for (mode, key_actions) in mode_info.keybinds {\n                            let mode_str = helper::modes_to_string(mode).cyan().bold().to_string();\n                            for (key, actions) in key_actions {\n                                let key_str = key.to_string();\n                                let action_str =\n                                    helper::actions_to_string(actions).cyan().bold().to_string();\n                                self.keybinds.insert(\n                                    format!(\"Mode: {}, Action: {}\", mode_str, action_str),\n                                    key_str,\n                                );\n                            }\n                        }\n                    }\n                }\n\n                should_render = true;\n            }\n            _ => (),\n        };\n\n        should_render\n    }\n\n    fn render(&mut self, _rows: usize, _cols: usize) {\n        for (key, value) in &self.filtered_keybinds() {\n            println!(\n                \"{} {:width$} {} {}\",\n                \"-\".green(),\n                key,\n                \"->\".green(),\n                value.cyan().bold(),\n                width = &self.max_key_length()\n            );\n        }\n        println!();\n        println!(\n            \"{} {}\",\n            \">\".cyan().bold(),\n            if self.filter.is_empty() {\n                \"Search: _\".cyan().bold().to_string()\n            } else {\n                format!(\"{}{}\", \"Search: \", self.filter)\n                    .cyan()\n                    .bold()\n                    .to_string()\n            }\n        );\n    }\n}\n"
  }
]