aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Qin <richard.qin.x@gmail.com>2026-04-13 04:50:49 +0800
committerRichard Qin <richard.qin.x@gmail.com>2026-04-13 04:50:49 +0800
commitd4f78be6f231b5289eb1c658d1f67006b7d884dd (patch)
tree8d27785fb97745f231e9879eb9bff81e8c225f60
parent8449f5fcefc5406f1666257bacb3bb1afda978e1 (diff)
downloadrwebbrowser-d4f78be6f231b5289eb1c658d1f67006b7d884dd.tar.gz
rwebbrowser-d4f78be6f231b5289eb1c658d1f67006b7d884dd.tar.xz
feat: move URL formatting to Browser class and update documentation
-rw-r--r--README.md83
-rw-r--r--include/ricochet/core/browser.hh1
-rw-r--r--src/core/browser.cc50
-rw-r--r--src/main.cc17
4 files changed, 99 insertions, 52 deletions
diff --git a/README.md b/README.md
index fd300d2..a09bf4a 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,19 @@ Modern browsing has become a minefield of non-free scripts, tracking pixels, and
* **Minimalist:** Focused entirely on text and structure.
* **Distraction-Free:** No ads, no popups, no auto-playing media. Just the data you came for.
+## Instructions
+- Keyboard-Driven Navigation: Fully controllable via Vim-style keybindings (j/k for scrolling, H/L for history).
+
+- Link Hinting: Press f to highlight all links with two-letter codes. Jump instantly without using a mouse or typing long numbers.
+
+- Privacy First: Industrial-grade Cookie Domain Isolation ensures your session data is never leaked across sites.
+
+- Fast Search: Built-in "Find in Page" (n/N) with real-time ANSI highlighting.
+
+- Persistent Data: Bookmarks and Browsing History are automatically saved to ~/.ricochet/ for a seamless experience.
+
+- Highly Configurable: Customize your User-Agent and default Homepage via a simple config file.
+
## Key Features
- [x] **High-Performance C++ Core:** Native speed with minimal memory footprint.
- [x] **Robust HTML5 Parser:** A custom, fault-tolerant DOM builder for the "wild" web.
@@ -23,6 +36,40 @@ Ricochet is built with a strictly modular approach:
* **`Layout`**: Calculates box models and word-wrapping for terminal constraints.
* **`TUI`**: An event-driven terminal UI handling viewport rendering and user input.
+## Usage
+```bash
+# Start with default homepage
+./build/bin/ricochet
+
+# Open a specific URL
+./build/bin/ricochet https://www.gnu.org
+
+# Use DuckDuckGo smart search
+./build/bin/ricochet "linux kernel news"
+```
+
+## Navigation
+| Key | Action |
+| :--- | :--- |
+| `j / k` | Scroll Down / Up |
+| `f` | Follow Link (Hint Mode) |
+| `n / N` | Find in Page / Next Match |
+| `H / L` | History Back / Forward |
+| `h` | View Browsing History |
+| `b / B` | Add Bookmark / View Bookmarks |
+| `/` | Open URL Prompt |
+| `i` | Form Input Mode |
+| `?` | Show Help Manual |
+| `q` | Quit |
+
+## Configuration
+Ricochet stores data in ~/.ricochet/. You can create config.txt to customize your experience:
+
+```plaintext
+homepage=https://v2ex.com
+user_agent=MyCustomBrowser/1.0
+```
+
## Getting Started
### Prerequisites
@@ -33,26 +80,35 @@ To build Ricochet, ensure your environment meets the following requirements:
* `clang-format` for automated code styling.
* `clang-tidy` for static analysis and linting.
-### Build Instructions
+### Building from Source
Ricochet enforces out-of-source builds to keep the project structure clean. By default, the project builds in Debug mode with Address and Undefined Behavior sanitizers enabled.
+#### 1. Clone the repository
```bash
-# 1. Clone the repository
git clone https://github.com/yourusername/ricochet.git
cd ricochet
+```
-# 2. Configure the project
-# This will generate compile commands and set the build type to Release
+#### 2. Configure the project
+This will generate compile commands and set the build type to Release
+```bash
cmake -B build -DCMAKE_BUILD_TYPE=Release
+```
-# 3. Compile the project using all available cores
+#### 3. Compile the project using all available cores
+```bash
cmake --build build -j$(nproc)
+```
-# 4. Launch Ricochet
-# The executable is located in the bin/ directory
-./build/bin/ricochet https://wikipedia.org
+### Install
+To install Ricochet to your system (defaulting to /usr/local/bin), run the following command with root privileges:
+
+```bash
+sudo cmake --install build
```
+This will install the `ricochet` executable to the `bin` destination and required libraries to `lib`.
+
### Build Parameters & Configuration
You can customize the build by passing `-D<VAR>=<VALUE>` to the initial `cmake -B build` command.
@@ -94,15 +150,8 @@ To install the compiled binaries to your system, use:
cmake --install build --prefix /usr/local
```
This installs the `ricochet` binary to `bin` and supporting libraries to `lib`.
-## Navigation
-| Key | Action |
-| :--- | :--- |
-| `j / k` | Scroll Down / Up |
-| `Tab` | Cycle through links |
-| `Enter` | Follow selected link |
-| `b` | Go Back in history |
-| `u` | Enter new URL |
-| `q` | Quit Ricochet |
+
+
## Acknowledgments
The low-level POSIX socket wrappers in `src/net/sys/` are adapted from the Minnow networking framework developed for Stanford University's CS144 course. These utilities are used gracefully to handle file descriptors and network interfaces.
diff --git a/include/ricochet/core/browser.hh b/include/ricochet/core/browser.hh
index 36e876d..ab7a473 100644
--- a/include/ricochet/core/browser.hh
+++ b/include/ricochet/core/browser.hh
@@ -33,6 +33,7 @@ public:
Browser( Browser&& ) = delete;
Browser& operator=( Browser&& ) = delete;
+ static std::string format_url( std::string input );
static std::string get_configured_homepage();
static int run( std::string_view initial_url );
};
diff --git a/src/core/browser.cc b/src/core/browser.cc
index 571783a..c4dbb08 100644
--- a/src/core/browser.cc
+++ b/src/core/browser.cc
@@ -412,30 +412,6 @@ void draw_view( const tui::Terminal& terminal,
std::cout.flush();
}
-std::string format_url( std::string input )
-{
- if ( input.empty() ) {
- return input;
- }
-
- if ( input.starts_with( "http://" ) || input.starts_with( "https://" ) ) {
- return input;
- }
-
- const bool is_domain = input.contains( '.' ) && !input.contains( ' ' );
- if ( is_domain ) {
- input.insert( 0, "https://" );
- return input;
- }
-
- for ( char& ch : input ) {
- if ( ch == ' ' ) {
- ch = '+';
- }
- }
- return "https://lite.duckduckgo.com/lite/?q=" + input;
-}
-
std::string get_url_input( const tui::Terminal& terminal )
{
auto [width, height] = terminal.get_size();
@@ -468,7 +444,7 @@ std::string get_url_input( const tui::Terminal& terminal )
}
terminal.show_cursor( false );
- return format_url( std::move( input ) );
+ return Browser::format_url( std::move( input ) );
}
// std::string get_link_input( const tui::Terminal& terminal )
@@ -1003,6 +979,30 @@ std::vector<std::string> wrap_lines( const std::vector<std::string>& original_li
} // namespace
+std::string Browser::format_url( std::string input )
+{
+ if ( input.empty() ) {
+ return input;
+ }
+
+ if ( input.starts_with( "http://" ) || input.starts_with( "https://" ) ) {
+ return input;
+ }
+
+ const bool is_domain = input.contains( '.' ) && !input.contains( ' ' );
+ if ( is_domain ) {
+ input.insert( 0, "https://" );
+ return input;
+ }
+
+ for ( char& ch : input ) {
+ if ( ch == ' ' ) {
+ ch = '+';
+ }
+ }
+ return "https://lite.duckduckgo.com/lite/?q=" + input;
+}
+
std::string Browser::get_configured_homepage()
{
std::ifstream file( get_config_path( "config.txt" ) );
diff --git a/src/main.cc b/src/main.cc
index 562861a..d27ab55 100644
--- a/src/main.cc
+++ b/src/main.cc
@@ -16,7 +16,6 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
-#include <fstream>
#include <iostream>
#include <span>
#include <string_view>
@@ -42,13 +41,6 @@ int main( int argc, char* argv[] )
ricochet::core::print_license_notice();
- std::string start_url;
- if ( args.size() < 2 ) {
- start_url = ricochet::core::Browser::get_configured_homepage();
- } else {
- start_url = std::string( args[1] );
- }
-
if ( args.size() >= 2 && args[1] == "show" ) {
if ( args.size() >= 3 && args[2] == "w" ) {
ricochet::core::show_warranty();
@@ -63,10 +55,15 @@ int main( int argc, char* argv[] )
return 1;
}
- if ( !start_url.starts_with( "http://" ) && !start_url.starts_with( "https://" ) ) {
- start_url.insert( 0, "https://" );
+ std::string start_url;
+ if ( args.size() < 2 ) {
+ start_url = ricochet::core::Browser::get_configured_homepage();
+ } else {
+ start_url = std::string( args[1] );
}
+ start_url = ricochet::core::Browser::format_url( std::move( start_url ) );
+
try {
return ricochet::core::Browser::run( start_url );
} catch ( const std::exception& e ) {