┌ All | Unread | Favs | Read ──── Feeds ┐┌─────────────────────────────────────────────────────┐
│ ││[TWiR] This Week in Rust 637 │
│ [Hacker News] US Customs destroys ra ││Date: 2026-02-04 │
│ [Hacker News] Lawmakers say US Militar││Link: https://this-week-in-rust.org/blog/2026/02/04/t│
│ [Hacker News] MitID, Denmarks sole dig││Tags: This Week in Rust │
│ [Hacker News] F-Droid Board of Directo││─────────────────────────────────────────────────────│
│ [Hacker News] Dyson settles forced lab││Hello and welcome to another issue of This Week in Ru│
│ [Hacker News] Breaking Free (2026-02-2││This is a weekly summary of its progress and communit│
│ [Hacker News] Working on Pharo Smallta││on mastodon.social, orsend us a pull request. Want to│
│ [Hacker News] Ubicloud (YC W24): Softw││ │
│ [Hacker News] The complete Manic Miner││This Week in Rust is openly developed on GitHub and a│
└───────────────────────────────────────┘└─────────────────────────────────────────────────────┘
A blazing-fast terminal RSS reader, built with Rust and ratatui.
You live in the terminal. Your RSS reader should too.
rs2 is minimal by philosophy and fast by design — feeds load concurrently in the background while the UI is instantly responsive. No Electron, no browser tab, no distractions.
| Feature | Details |
|---|---|
| Vi-style navigation | h/j/k/l to move — feels like home |
| Concurrent fetching | Feeds load in parallel; UI appears instantly and items stream in as they arrive |
| Sidebar tabs | Filter by All · Unread · Favorites · Read with [ and ] |
| Favorites & Read tracking | Mark items with f and r; state persists across sessions |
| Open in browser | Press o to open the current item's link via xdg-open |
| Collapsible sidebar | Press Tab or t to go full-screen on the content panel |
| Reflow on resize | HTML is stripped at render time so text always fits the terminal width |
| Graceful degradation | A broken feed shows a warning but never prevents the rest from loading |
| Fully remappable keys | Every keybind is configurable in ~/.config/rs2/config.toml |
From source (recommended):
git clone https://github.com/alexmrtr/rs2
cd rs2
cargo install --path . # installs to ~/.cargo/bin/rs2Or build the binary manually:
cargo build --release
# binary at target/release/rs2Requirements: Rust 1.85+ · Linux/macOS ·
xdg-open(for browser integration on Linux)
mkdir -p ~/.config/rs2
cp config.toml.example ~/.config/rs2/config.toml
# Edit to add your feeds[[feeds]]
name = "Rust Blog"
url = "https://blog.rust-lang.org/feed.xml"
[[feeds]]
name = "TWiR"
url = "https://this-week-in-rust.org/rss.xml"
[[feeds]]
name = "Hacker News"
url = "https://hnrss.org/frontpage"
[[feeds]]
name = "LWN"
url = "https://lwn.net/headlines/rss"
# Optional — omit any key to keep the default.
[keybinds]
quit = "q"
nav_down = "j"
nav_up = "k"
nav_left = "h"
nav_right = "l"
scroll_down = "d"
scroll_up = "u"
toggle_favorite = "f"
toggle_read = "r"
open_link = "o"
tab_next = "]"
tab_prev = "["
toggle_help = "?"
toggle_sidebar = "t"State (favorites, read items) is persisted to ~/.config/rs2/state.toml automatically.
| Key | Action |
|---|---|
j / k |
Move down / up in the feed list |
l |
Focus the content panel |
h |
Focus the feed list |
d / u |
Scroll content down / up |
Ctrl-n / Ctrl-p |
Scroll content down / up (always, regardless of focus) |
Tab or t |
Toggle the feed list sidebar |
| Key | Action |
|---|---|
] / [ |
Next / previous sidebar tab |
Ctrl-l / Ctrl-h |
Next / previous sidebar tab |
f |
Toggle favorite on current item ★ |
r |
Toggle read on current item |
o |
Open item link in browser |
| Key | Action |
|---|---|
? |
Toggle help overlay |
q |
Quit |
All keys are remappable. See the config section above.
src/
main.rs Entry point — wires config, fetcher, and event loop
config.rs TOML config loading; missing file returns a safe default
error.rs Single Error enum so all callers use ? uniformly
feed.rs HttpFetcher trait + UreqFetcher; fully mockable for tests
keybinds.rs Maps KeyEvent → AppAction; decouples raw input from state
app.rs App state machine (handle_action is pure, no I/O)
state.rs Persists favorites and read items to state.toml
ui.rs ratatui rendering; HTML→Markdown stripped at render time
The design intentionally separates concerns:
handle_actionis pure — no I/O, no terminal calls, 100% unit-testable.HttpFetcheris a trait — swap in aMockHttpFetcherfor tests without ever hitting the network.- HTML is stripped at render time — not at fetch time — so content always reflows correctly when the terminal is resized.
- Feeds run in background threads — one
mpscchannel drains results into the main loop; the UI is never blocked.
# Run all tests (network tests skipped by default)
cargo test
# Include the live network test
cargo test -- --ignored
# Coverage report (requires cargo-llvm-cov)
cargo llvm-cov --all- Search / filter across all items
- Atom feed support improvements
- Mouse support
- Configurable color themes
- OPML import/export
Pull requests are welcome! Please open an issue first for major changes.
- Fork the repo
- Create a feature branch (
git checkout -b feat/my-feature) - Commit your changes
- Open a PR
MIT © Alexandre Marques Tortoza Canoa
I’m not fluent in Rust, and this is a personal project. I created it to solve a problem I encountered, but feel free to use, modify, or adapt it however you like. I hope you find it useful!
make code not war 🦀