{"slug": "peektea-narrows-its-gaze-filter-as-you-type-and-hidden-files", "title": "peektea narrows its gaze 👀 filter-as-you-type and hidden files", "summary": "Maneshwar has added filter-as-you-type and hidden file toggle features to peektea, a terminal-based file browser built with Bubble Tea. Pressing `/` activates a text input that instantly narrows visible entries, while pressing `.` toggles the display of dotfiles, with both filters composable simultaneously. The implementation uses the `textinput` component from the charmbracelet/bubbles library and a `withFilters()` function that recomputes the visible entry list based on the current filter query and hidden file state.", "body_md": "*Hello, I'm Maneshwar. I'm building git-lrc, a Micro AI code reviewer that runs on every commit. It is free and source-available on Github. Star git-lrc to help devs discover the project. Do give it a try and share your feedback.*\n\nLast time I ended with two items left on the list.\n\nFilter as you type— Bubble Tea's`textinput`\n\ncomponent from bubbles is sitting there waiting\n\nHidden file toggle— show/hide dotfiles\n\nBoth ship today.\n\nPress `/`\n\nand start typing, the list narrows instantly.\n\nPress `.`\n\nand dotfiles appear.\n\nPress it again and they vanish.\n\nThe `/`\n\nkey enters filter mode.\n\nA text input appears at the bottom of the panel right above the hint bar, like [vim](https://github.com/vim/vim)'s command line.\n\nType anything and only matching entries stay visible.\n\nPress `esc`\n\nto clear it.\n\nThe component doing the work is `textinput`\n\nfrom [charmbracelet/bubbles](https://github.com/charmbracelet/bubbles), a library of ready-made Bubble Tea components.\n\nWiring it into the model is straightforward:\n\n```\ntype model struct {\n    // ...\n    filterInput textinput.Model\n    filtering   bool\n}\n```\n\nWhen `/`\n\nis pressed, focus the input and return `textinput.Blink`\n\n, that's the command that starts the cursor blinking animation:\n\n```\ncase \"/\":\n    m.filtering = true\n    m.filterInput.Focus()\n    return m, textinput.Blink\n```\n\nWhile filtering, most keystrokes go straight to the textinput's own `Update`\n\n.\n\nNavigation keys (`↑↓`\n\n) are intercepted first so you can still move the cursor while typing:\n\n```\nif m.filtering {\n    switch msg.String() {\n    case \"up\", \"k\":\n        if m.cursor > 0 { m.cursor-- }\n    case \"down\", \"j\":\n        if m.cursor < len(m.entries)-1 { m.cursor++ }\n    case \"esc\":\n        m.filtering = false\n        m.filterInput.Blur()\n        m.filterInput.SetValue(\"\")\n        m = m.withFilters()\n    default:\n        var tiCmd tea.Cmd\n        m.filterInput, tiCmd = m.filterInput.Update(msg)\n        m = m.withFilters()\n        return m, tiCmd\n    }\n}\n```\n\nThe `tiCmd`\n\nreturned by `m.filterInput.Update`\n\ncarries the next blink tick.\n\nYou have to pass it back out of `Update`\n\n, drop it and the cursor freezes.\n\nThe model now stores two entry slices: `allEntries`\n\n(everything `os.ReadDir`\n\nreturned) and `entries`\n\n(what's visible after filters).\n\nEvery filter change calls `withFilters()`\n\nto recompute:\n\n```\nfunc (m model) withFilters() model {\n    q := strings.ToLower(m.filterInput.Value())\n    var filtered []os.DirEntry\n    for _, e := range m.allEntries {\n        if !m.showHidden && strings.HasPrefix(e.Name(), \".\") {\n            continue\n        }\n        if q != \"\" && !strings.Contains(strings.ToLower(e.Name()), q) {\n            continue\n        }\n        filtered = append(filtered, e)\n    }\n    m.entries = filtered\n    if m.cursor >= len(m.entries) {\n        m.cursor = max(0, len(m.entries)-1)\n    }\n    return m\n}\n```\n\nHidden toggle and text filter compose naturally, you can filter by name with dotfiles visible or hidden simultaneously.\n\nAdding a third filter later means touching one function.\n\n`withFilters`\n\nreturns a new model value rather than mutating in place, which fits cleanly with Bubble Tea's immutable-update pattern.\n\nThe `.`\n\nkey flips `showHidden`\n\nand calls `withFilters()`\n\n:\n\n```\ncase \".\":\n    m.showHidden = !m.showHidden\n    m = m.withFilters()\n    needPreview = true\n```\n\nThe hint bar reflects the current state so you always know where you are:\n\n```\n. show hidden   ← dotfiles hidden\n. hide hidden   ← dotfiles visible\n```\n\nNavigating into a directory clears the filter, the search you ran in one folder doesn't carry over to its children.\n\nMakes the behaviour predictable without any extra state to manage.\n\nThe filter input sits at the bottom of the panel, one line above the hint bar.\n\nThat's the slot vim uses for its command line, `/pattern`\n\n, `:w`\n\n, `:q`\n\nso it feels immediately familiar.\n\nWhen filtering is active the text input renders there instead of the hint.\n\nWhen you press `enter`\n\nto confirm and leave filter mode, the active filter stays visible:\n\n```\n/main  esc to clear\n↑/↓  →/enter  o open  / filter  . hide hidden  p preview  ←/h  q\n```\n\nThe hint never disappears, even in filter mode it's always one line below.\n\nThe layout calculates how many rows the file list consumed and pads blank lines to push both the filter bar and the hint bar to the very bottom of the terminal.\n\nAI agents write code fast. They also silently remove logic, change behavior, and introduce bugs — without telling you. You often find out in production.\n\ngit-lrc fixes this. It hooks into git commit and reviews every diff before it lands. 60-second setup. Completely free.\n\nAny feedback or contributors are welcome! It's online, source-available, and ready for anyone to use.\n\n⭐ Star it on GitHub:\n\n| [🇩🇰 Dansk](https://github.com/HexmosTech/git-lrc/readme/README.da.md) | [🇪🇸 Español](https://github.com/HexmosTech/git-lrc/readme/README.es.md) | [🇮🇷 Farsi](https://github.com/HexmosTech/git-lrc/readme/README.fa.md) | [🇫🇮 Suomi](https://github.com/HexmosTech/git-lrc/readme/README.fi.md) | [🇯🇵 日本語](https://github.com/HexmosTech/git-lrc/readme/README.ja.md) | [🇳🇴 Norsk](https://github.com/HexmosTech/git-lrc/readme/README.nn.md) | [🇵🇹 Português](https://github.com/HexmosTech/git-lrc/readme/README.pt.md) | [🇷🇺 Русский](https://github.com/HexmosTech/git-lrc/readme/README.ru.md) | [🇦🇱 Shqip](https://github.com/HexmosTech/git-lrc/readme/README.sq.md) | [🇨🇳 中文](https://github.com/HexmosTech/git-lrc/readme/README.zh.md) |\n\nAI agents write code fast. They also *silently remove logic*, change behavior, and introduce bugs -- without telling you. You often find out in production.\n\n** git-lrc fixes this.** It hooks into\n\n`git commit`\n\nand reviews every diff git-lrc-intro-60s.mp4See git-lrc catch serious security issues such as leaked credentials, expensive cloud operations, and sensitive material in log statements", "url": "https://wpnews.pro/news/peektea-narrows-its-gaze-filter-as-you-type-and-hidden-files", "canonical_source": "https://dev.to/lovestaco/peektea-narrows-its-gaze-filter-as-you-type-and-hidden-files-23ic", "published_at": "2026-06-04 17:22:56+00:00", "updated_at": "2026-06-04 17:42:25.259493+00:00", "lang": "en", "topics": ["ai-tools"], "entities": ["Maneshwar", "git-lrc", "Bubble Tea", "charmbracelet/bubbles", "vim"], "alternates": {"html": "https://wpnews.pro/news/peektea-narrows-its-gaze-filter-as-you-type-and-hidden-files", "markdown": "https://wpnews.pro/news/peektea-narrows-its-gaze-filter-as-you-type-and-hidden-files.md", "text": "https://wpnews.pro/news/peektea-narrows-its-gaze-filter-as-you-type-and-hidden-files.txt", "jsonld": "https://wpnews.pro/news/peektea-narrows-its-gaze-filter-as-you-type-and-hidden-files.jsonld"}}