aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Qin <richard.qin.x@gmail.com>2026-10-16 22:35:09 +0800
committerRichard Qin <richard.qin.x@gmail.com>2026-10-16 22:35:09 +0800
commit31a6c85731b439dbeb64eacf8f4fc461c0a6264c (patch)
tree34f604cfbe8a2807c1b4adf5323b926102d6a9ab
parent1621b3dbfaccb4e2960adba4daf81c967e5cdf9e (diff)
downloadrwebbrowser-31a6c85731b439dbeb64eacf8f4fc461c0a6264c.tar.gz
rwebbrowser-31a6c85731b439dbeb64eacf8f4fc461c0a6264c.tar.xz
Remove legacy terminal UI infrastructure and rename license file
-rw-r--r--COPYING (renamed from LICENSE)0
-rw-r--r--include/ricochet/core/browser.hh5
-rw-r--r--include/ricochet/core/form_handler.hh11
-rw-r--r--include/ricochet/core/link_hints.hh27
-rw-r--r--include/ricochet/core/search_handler.hh23
-rw-r--r--include/ricochet/core/types.hh4
-rw-r--r--include/ricochet/core/ui_input.hh29
-rw-r--r--include/ricochet/core/ui_view.hh37
-rw-r--r--include/ricochet/core/utils.hh2
-rw-r--r--include/ricochet/tui/terminal.hh56
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/core/browser.cc154
-rw-r--r--src/core/form_handler.cc101
-rw-r--r--src/core/link_hints.cc104
-rw-r--r--src/core/search_handler.cc81
-rw-r--r--src/core/ui_input.cc94
-rw-r--r--src/core/ui_view.cc103
-rw-r--r--src/core/utils.cc33
-rw-r--r--src/tui/terminal.cc90
19 files changed, 2 insertions, 953 deletions
diff --git a/LICENSE b/COPYING
index f288702..f288702 100644
--- a/LICENSE
+++ b/COPYING
diff --git a/include/ricochet/core/browser.hh b/include/ricochet/core/browser.hh
index ab7a473..fabcba4 100644
--- a/include/ricochet/core/browser.hh
+++ b/include/ricochet/core/browser.hh
@@ -18,7 +18,7 @@
#pragma once
-#include <string_view>
+#include <string>
namespace ricochet::core {
@@ -35,7 +35,6 @@ public:
static std::string format_url( std::string input );
static std::string get_configured_homepage();
- static int run( std::string_view initial_url );
};
-} // namespace ricochet::core \ No newline at end of file
+} // namespace ricochet::core
diff --git a/include/ricochet/core/form_handler.hh b/include/ricochet/core/form_handler.hh
index 5abf148..d95bd02 100644
--- a/include/ricochet/core/form_handler.hh
+++ b/include/ricochet/core/form_handler.hh
@@ -12,7 +12,6 @@
#include "ricochet/core/types.hh"
#include "ricochet/render/renderer.hh"
-#include "ricochet/tui/terminal.hh"
#include <cstddef>
#include <string>
#include <vector>
@@ -25,14 +24,4 @@ InputAction submit_form( const render::InputField& target_input,
std::vector<HttpRequest>& history,
std::size_t& history_idx );
-void update_input_value( PageData& page_data, std::size_t index, const std::string& query );
-void update_single_line_ui( std::string& line, const std::string& marker, const render::InputField& in );
-void update_toggle_ui( PageData& page_data );
-
-InputAction handle_form_input( const tui::Terminal& terminal,
- PageData& page_data,
- const std::string& current_url,
- std::vector<HttpRequest>& history,
- std::size_t& history_idx );
-
} // namespace ricochet::core
diff --git a/include/ricochet/core/link_hints.hh b/include/ricochet/core/link_hints.hh
deleted file mode 100644
index 5da4846..0000000
--- a/include/ricochet/core/link_hints.hh
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Ricochet - A minimalist CLI web browser for fast, distraction-free navigation.
- * Copyright (C) 2026 Richard Qin
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- */
-
-#pragma once
-
-#include "ricochet/core/types.hh"
-#include "ricochet/tui/terminal.hh"
-#include <string>
-
-namespace ricochet::core {
-
-std::string index_to_hint( std::size_t index );
-void toggle_link_hints( PageData& page_data, bool show );
-void handle_follow_link( const tui::Terminal& terminal,
- PageData& page_data,
- std::string& current_url,
- std::size_t& scroll_y,
- bool& navigate );
-
-} // namespace ricochet::core
diff --git a/include/ricochet/core/search_handler.hh b/include/ricochet/core/search_handler.hh
deleted file mode 100644
index 7053be8..0000000
--- a/include/ricochet/core/search_handler.hh
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Ricochet - A minimalist CLI web browser for fast, distraction-free navigation.
- * Copyright (C) 2026 Richard Qin
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- */
-
-#pragma once
-
-#include "ricochet/core/types.hh"
-#include <cstddef>
-#include <string>
-
-namespace ricochet::core {
-
-void find_search_matches( PageData& page_data, const std::string& query );
-void apply_search_highlight( PageData& page_data, const std::string& query );
-void execute_search( PageData& page_data, const std::string& query, std::size_t& scroll_y, bool next_match );
-
-} // namespace ricochet::core
diff --git a/include/ricochet/core/types.hh b/include/ricochet/core/types.hh
index bd7e819..ef48016 100644
--- a/include/ricochet/core/types.hh
+++ b/include/ricochet/core/types.hh
@@ -31,10 +31,6 @@ struct PageData
std::vector<std::string> links;
std::vector<render::InputField> inputs;
std::string title;
- std::vector<std::string> original_lines {};
- std::string last_search {};
- std::size_t current_match_idx { 0 };
- std::vector<std::size_t> match_lines {};
};
struct HttpRequest
diff --git a/include/ricochet/core/ui_input.hh b/include/ricochet/core/ui_input.hh
deleted file mode 100644
index bf71685..0000000
--- a/include/ricochet/core/ui_input.hh
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Ricochet - A minimalist CLI web browser for fast, distraction-free navigation.
- * Copyright (C) 2026 Richard Qin
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- */
-
-#pragma once
-
-#include "ricochet/tui/terminal.hh"
-#include <string>
-
-namespace ricochet::core {
-
-std::string get_url_input( const tui::Terminal& terminal );
-std::string get_terminal_input( const tui::Terminal& terminal, const std::string& prompt );
-
-} // namespace ricochet::core
diff --git a/include/ricochet/core/ui_view.hh b/include/ricochet/core/ui_view.hh
deleted file mode 100644
index d9a55fa..0000000
--- a/include/ricochet/core/ui_view.hh
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Ricochet - A minimalist CLI web browser for fast, distraction-free navigation.
- * Copyright (C) 2026 Richard Qin
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- */
-
-#pragma once
-
-#include "ricochet/tui/terminal.hh"
-
-#include <string>
-#include <string_view>
-#include <vector>
-
-namespace ricochet::core {
-
-std::string build_footer( std::string_view url, std::size_t width );
-
-void draw_view( const tui::Terminal& terminal,
- const std::vector<std::string>& lines,
- std::size_t scroll_y,
- std::string_view url,
- std::string_view title );
-
-} // namespace ricochet::core
diff --git a/include/ricochet/core/utils.hh b/include/ricochet/core/utils.hh
index d9f58dd..61d480b 100644
--- a/include/ricochet/core/utils.hh
+++ b/include/ricochet/core/utils.hh
@@ -18,7 +18,6 @@
#pragma once
-#include <cstddef>
#include <string>
#include <vector>
@@ -27,6 +26,5 @@ namespace ricochet::core {
std::vector<std::string> split_into_lines( const std::string& text );
std::string normalize_url( const std::string& target, const std::string& current_url );
std::string strip_ddg_tracker( std::string target );
-std::vector<std::string> wrap_lines( const std::vector<std::string>& original_lines, std::size_t wrap_width );
} // namespace ricochet::core
diff --git a/include/ricochet/tui/terminal.hh b/include/ricochet/tui/terminal.hh
deleted file mode 100644
index 2942a2a..0000000
--- a/include/ricochet/tui/terminal.hh
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Ricochet - A minimalist CLI web browser for fast, distraction-free navigation.
- * Copyright (C) 2026 Richard Qin
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- */
-
-#pragma once
-
-#include <termios.h>
-#include <utility>
-
-namespace ricochet::tui {
-
-class Terminal
-{
-public:
- Terminal();
- ~Terminal();
-
- Terminal( const Terminal& ) = delete;
- Terminal& operator=( const Terminal& ) = delete;
- Terminal( Terminal&& ) = delete;
- Terminal& operator=( Terminal&& ) = delete;
-
- // Read a single key
- char read_key() const;
-
- // Clear screen and move cursor to top-left
- void clear_screen() const;
-
- // Get terminal size
- std::pair<std::size_t, std::size_t> get_size() const;
-
- // Move cursor to a specific position
- void move_cursor( std::size_t row, std::size_t col ) const;
-
- // Show or hide cursor
- void show_cursor( bool visible ) const;
-
-private:
- struct termios original_termios_ {}; // Save terminal original state
-};
-
-} // namespace ricochet::tui \ No newline at end of file
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index dcc8f49..e46ac9a 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -17,4 +17,3 @@ target_link_libraries(ricochet_core
add_executable(ricochet ${MAIN_SRC})
target_link_libraries(ricochet PRIVATE ricochet_core)
-# target_link_libraries(ricochet PRIVATE ricochet_core curl ncurses) \ No newline at end of file
diff --git a/src/core/browser.cc b/src/core/browser.cc
index 86a5096..c413a0d 100644
--- a/src/core/browser.cc
+++ b/src/core/browser.cc
@@ -18,117 +18,12 @@
#include "ricochet/core/browser.hh"
-#include <cstddef>
-#include <cstdlib>
#include <fstream>
-#include <iostream>
-#include <sys/stat.h>
-#include "ricochet/core/form_handler.hh"
-#include "ricochet/core/link_hints.hh"
#include "ricochet/core/local_data.hh"
-#include "ricochet/core/page_loader.hh"
-#include "ricochet/core/search_handler.hh"
-#include "ricochet/core/ui_input.hh"
-#include "ricochet/core/ui_view.hh"
-#include "ricochet/core/utils.hh"
namespace ricochet::core {
-namespace {
-
-InputAction push_history( const std::string& url, std::vector<HttpRequest>& history, std::size_t& history_idx )
-{
- history.resize( history_idx + 1 );
- history.push_back( HttpRequest { .url = url, .method = "GET", .body = "" } );
- history_idx++;
- return InputAction::Navigate;
-}
-
-InputAction process_key( char c,
- const tui::Terminal& terminal,
- PageData& page_data,
- std::string& current_url,
- std::vector<HttpRequest>& history,
- std::size_t& history_idx, // NOLINT(bugprone-easily-swappable-parameters)
- std::size_t& scroll_y ) // NOLINT(bugprone-easily-swappable-parameters)
-{
- auto [width, height] = terminal.get_size();
- const std::size_t view_h = ( height > 1 ) ? ( height - 1 ) : 1;
-
- switch ( c ) {
- case 'q':
- return InputAction::Quit;
- case 'j':
- if ( scroll_y + view_h < page_data.lines.size() ) {
- scroll_y++;
- }
- break;
- case 'k':
- if ( scroll_y > 0 ) {
- scroll_y--;
- }
- break;
- case 'H':
- if ( history_idx > 0 ) {
- history_idx--;
- return InputAction::Navigate;
- }
- break;
- case 'L':
- if ( history_idx + 1 < history.size() ) {
- history_idx++;
- return InputAction::Navigate;
- }
- break;
- case 'r':
- return InputAction::Navigate;
- case 'b':
- save_bookmark( page_data.title, current_url );
- break;
- case 'B':
- return push_history( "ricochet://bookmarks", history, history_idx );
- case '?':
- return push_history( "ricochet://help", history, history_idx );
- case 'h':
- return push_history( "ricochet://history", history, history_idx );
- case 'n': {
- const std::string query = get_terminal_input( terminal, "Find in Page:" );
- execute_search( page_data, query, scroll_y, false );
- break;
- }
- case 'N':
- execute_search( page_data, page_data.last_search, scroll_y, true );
- break;
- case '/': {
- const std::string next_url = get_url_input( terminal );
- if ( !next_url.empty() ) {
- return push_history( next_url, history, history_idx );
- }
- break;
- }
- case 'f': {
- const std::string old_url = current_url;
- bool nav = false;
- handle_follow_link( terminal, page_data, current_url, scroll_y, nav );
- if ( nav && current_url != old_url ) {
- return push_history( current_url, history, history_idx );
- }
- break;
- }
- case 'i':
- if ( !page_data.inputs.empty() ) {
- return handle_form_input( terminal, page_data, current_url, history, history_idx );
- }
- break;
- default:
- break;
- }
- return InputAction::None;
-}
-
-} // namespace
-
std::string Browser::format_url( std::string input )
{
if ( input.empty() ) {
@@ -168,53 +63,4 @@ std::string Browser::get_configured_homepage()
return "https://wikipedia.org";
}
-int Browser::run( std::string_view initial_url )
-{
- std::vector<HttpRequest> history;
- history.emplace_back( HttpRequest { .url = std::string( initial_url ), .method = "GET", .body = "" } );
- std::size_t history_idx = 0;
- const tui::Terminal terminal;
- terminal.show_cursor( false );
-
- while ( true ) {
- const HttpRequest current_req = history[history_idx];
- std::string current_url = current_req.url;
- terminal.clear_screen();
- std::cout << "-> Fetching: " << current_req.url << "...\r\n";
- std::cout.flush();
-
- auto page_data = load_page( current_req );
-
- static std::string last_recorded_url;
- if ( current_url != last_recorded_url && !current_url.starts_with( "ricochet://" ) ) {
- append_to_history( current_url, page_data.title );
- last_recorded_url = current_url;
- }
-
- auto [term_width, term_height] = terminal.get_size();
- const std::size_t wrap_width = ( term_width > 1 ) ? ( term_width - 1 ) : 80;
- page_data.lines = wrap_lines( page_data.lines, wrap_width );
- page_data.original_lines = page_data.lines;
-
- std::size_t scroll_y = 0;
- bool navigate = false;
-
- while ( !navigate ) {
- draw_view( terminal, page_data.lines, scroll_y, current_url, page_data.title );
- const char c = terminal.read_key();
-
- const InputAction action = process_key( c, terminal, page_data, current_url, history, history_idx, scroll_y );
- if ( action == InputAction::Quit ) {
- terminal.clear_screen();
- return 0;
- }
- if ( action == InputAction::Navigate ) {
- navigate = true;
- }
- }
- }
- terminal.clear_screen();
- return 0;
-}
-
} // namespace ricochet::core
diff --git a/src/core/form_handler.cc b/src/core/form_handler.cc
index 2d018c9..6100a30 100644
--- a/src/core/form_handler.cc
+++ b/src/core/form_handler.cc
@@ -17,7 +17,6 @@
*/
#include "ricochet/core/form_handler.hh"
-#include "ricochet/core/ui_input.hh"
#include "ricochet/core/utils.hh"
namespace ricochet::core {
@@ -62,104 +61,4 @@ InputAction submit_form( const render::InputField& target_input,
return InputAction::Navigate;
}
-void update_input_value( PageData& page_data, std::size_t index, const std::string& query )
-{
- page_data.inputs[index - 1].value = query;
- const std::string marker = "[I" + std::to_string( index ) + ":";
- const std::string replacement = "[I" + std::to_string( index ) + ":" + query + "]";
-
- auto update_lines = [&]( std::vector<std::string>& lines_arr ) {
- for ( auto& line : lines_arr ) {
- const std::size_t pos = line.find( marker );
- if ( pos != std::string::npos ) {
- const std::size_t end = line.find( ']', pos );
- if ( end != std::string::npos ) {
- line.replace( pos, end - pos + 1, replacement );
- }
- }
- }
- };
- update_lines( page_data.lines );
- update_lines( page_data.original_lines );
-}
-
-void update_single_line_ui( std::string& line, const std::string& marker, const render::InputField& in )
-{
- const std::string checked_str = marker + ( in.type == "checkbox" ? "[X] " : "(X) " ) + in.value + "]";
- const std::string unchecked_str = marker + ( in.type == "checkbox" ? "[ ] " : "( ) " ) + in.value + "]";
-
- const std::string& target_str = in.checked ? checked_str : unchecked_str;
- const std::string& old_str = in.checked ? unchecked_str : checked_str;
-
- const std::size_t pos = line.find( old_str );
- if ( pos != std::string::npos ) {
- line.replace( pos, old_str.length(), target_str );
- }
-}
-
-void update_toggle_ui( PageData& page_data )
-{
- for ( std::size_t i = 0; i < page_data.inputs.size(); ++i ) {
- const auto& in = page_data.inputs[i];
- if ( in.type != "checkbox" && in.type != "radio" ) {
- continue;
- }
- const std::string marker = "[I" + std::to_string( i + 1 ) + ":";
- for ( auto& line : page_data.lines ) {
- update_single_line_ui( line, marker, in );
- }
- for ( auto& line : page_data.original_lines ) {
- update_single_line_ui( line, marker, in );
- }
- }
-}
-
-InputAction handle_form_input( const tui::Terminal& terminal,
- PageData& page_data,
- const std::string& current_url,
- std::vector<HttpRequest>& history,
- std::size_t& history_idx )
-{
- const std::string num_input = get_terminal_input( terminal, "Select Input [#]:" );
- if ( num_input.empty() ) {
- return InputAction::None;
- }
- std::size_t index = 0;
- try {
- index = std::stoul( num_input );
- } catch ( ... ) {
- return InputAction::None;
- }
- if ( index == 0 || index > page_data.inputs.size() ) {
- return InputAction::None;
- }
-
- auto& target_input = page_data.inputs[index - 1];
- if ( target_input.type == "submit" || target_input.type == "button" ) {
- return submit_form( target_input, page_data.inputs, current_url, history, history_idx );
- }
-
- if ( target_input.type == "checkbox" || target_input.type == "radio" ) {
- if ( target_input.type == "radio" ) {
- for ( auto& in : page_data.inputs ) {
- if ( in.name == target_input.name && in.action == target_input.action ) {
- in.checked = false;
- }
- }
- target_input.checked = true;
- } else {
- target_input.checked = !target_input.checked;
- }
- update_toggle_ui( page_data );
- return InputAction::None;
- }
-
- const std::string query = get_terminal_input( terminal, "Enter Text [I" + std::to_string( index ) + "]:" );
- if ( query.empty() ) {
- return InputAction::None;
- }
- update_input_value( page_data, index, query );
- return InputAction::None;
-}
-
} // namespace ricochet::core
diff --git a/src/core/link_hints.cc b/src/core/link_hints.cc
deleted file mode 100644
index 77b91b8..0000000
--- a/src/core/link_hints.cc
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Ricochet - A minimalist CLI web browser for fast, distraction-free navigation.
- * Copyright (C) 2026 Richard Qin
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- */
-
-#include "ricochet/core/link_hints.hh"
-#include "ricochet/core/ui_view.hh"
-#include "ricochet/core/utils.hh"
-#include <iostream>
-
-namespace ricochet::core {
-
-std::string index_to_hint( std::size_t index )
-{
- const std::string alphabet = "asdfghjklqwertyuiopzxcvbnm";
- std::string hint;
- hint += alphabet[( index / alphabet.length() ) % alphabet.length()];
- hint += alphabet[index % alphabet.length()];
- return hint;
-}
-
-void toggle_link_hints( PageData& page_data, bool show )
-{
- const std::string hl_start = "\033[0;1;35;7m ";
- const std::string hl_end = " \033[0m";
-
- std::vector<std::string> formatted_hints;
- formatted_hints.reserve( page_data.links.size() );
- for ( std::size_t i = 0; i < page_data.links.size(); ++i ) {
- std::string h = hl_start;
- h += index_to_hint( i );
- h += hl_end;
- formatted_hints.push_back( std::move( h ) );
- }
-
- for ( auto& line : page_data.lines ) {
- for ( std::size_t i = 0; i < page_data.links.size(); ++i ) {
- const std::string marker = "{L:" + std::to_string( i + 1 ) + "}";
- if ( show ) {
- const std::size_t pos = line.find( marker );
- if ( pos != std::string::npos ) {
- line.replace( pos, marker.length(), formatted_hints[i] );
- }
- } else {
- const std::size_t pos = line.find( formatted_hints[i] );
- if ( pos != std::string::npos ) {
- line.replace( pos, formatted_hints[i].length(), marker );
- }
- }
- }
- }
-}
-
-void handle_follow_link( const tui::Terminal& terminal,
- PageData& page_data,
- std::string& current_url,
- std::size_t& scroll_y, // NOLINT(bugprone-easily-swappable-parameters)
- bool& navigate )
-{
- toggle_link_hints( page_data, true );
-
- draw_view( terminal, page_data.lines, scroll_y, current_url, page_data.title );
-
- auto [w, h] = terminal.get_size();
- terminal.move_cursor( h, 1 );
- std::cout << "\x1b[2K\033[1;35;7m Follow Hint (2 keys): \033[0m ";
- std::cout.flush();
-
- std::string input;
- input += terminal.read_key();
- std::cout << input[0];
- std::cout.flush();
- input += terminal.read_key();
-
- // bool found = false;
- for ( std::size_t i = 0; i < page_data.links.size(); ++i ) {
- if ( index_to_hint( i ) == input ) {
- std::string target = page_data.links[i];
- target = normalize_url( target, current_url );
- target = strip_ddg_tracker( target );
- current_url = target;
- navigate = true;
- // found = true;
- break;
- }
- }
-
- toggle_link_hints( page_data, false );
-}
-
-} // namespace ricochet::core
diff --git a/src/core/search_handler.cc b/src/core/search_handler.cc
deleted file mode 100644
index cab9e9c..0000000
--- a/src/core/search_handler.cc
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Ricochet - A minimalist CLI web browser for fast, distraction-free navigation.
- * Copyright (C) 2026 Richard Qin
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- */
-
-#include "ricochet/core/search_handler.hh"
-
-namespace ricochet::core {
-
-void find_search_matches( PageData& page_data, const std::string& query )
-{
- page_data.last_search = query;
- page_data.match_lines.clear();
- page_data.current_match_idx = 0;
- for ( std::size_t i = 0; i < page_data.original_lines.size(); ++i ) {
- if ( page_data.original_lines[i].find( query ) != std::string::npos ) {
- page_data.match_lines.push_back( i );
- }
- }
-}
-
-void apply_search_highlight( PageData& page_data, const std::string& query )
-{
- page_data.lines = page_data.original_lines;
- if ( page_data.match_lines.empty() ) {
- return;
- }
-
- const std::string hl_start = "\033[43;30m";
- const std::string hl_end = "\033[0m";
-
- for ( const auto match_idx : page_data.match_lines ) {
- auto& line = page_data.lines[match_idx];
- std::size_t pos = 0;
- std::string replacement;
- replacement.reserve( hl_start.length() + query.length() + hl_end.length() );
- replacement += hl_start;
- replacement += query;
- replacement += hl_end;
- while ( ( pos = line.find( query, pos ) ) != std::string::npos ) {
- line.replace( pos, query.length(), replacement );
- pos += hl_start.length() + query.length() + hl_end.length();
- }
- }
-}
-
-void execute_search( PageData& page_data, const std::string& query, std::size_t& scroll_y, bool next_match )
-{
- if ( query.empty() ) {
- return;
- }
-
- if ( !next_match || query != page_data.last_search ) {
- find_search_matches( page_data, query );
- apply_search_highlight( page_data, query );
- } else if ( !page_data.match_lines.empty() ) {
- page_data.current_match_idx = ( page_data.current_match_idx + 1 ) % page_data.match_lines.size();
- }
-
- if ( page_data.match_lines.empty() ) {
- return;
- }
-
- const std::size_t target_line = page_data.match_lines[page_data.current_match_idx];
- scroll_y = ( target_line > 5 ) ? ( target_line - 5 ) : 0;
-}
-
-} // namespace ricochet::core
diff --git a/src/core/ui_input.cc b/src/core/ui_input.cc
deleted file mode 100644
index 0f57dd1..0000000
--- a/src/core/ui_input.cc
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Ricochet - A minimalist CLI web browser for fast, distraction-free navigation.
- * Copyright (C) 2026 Richard Qin
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- */
-
-#include "ricochet/core/ui_input.hh"
-#include "ricochet/core/browser.hh"
-#include <iostream>
-
-namespace ricochet::core {
-
-std::string get_url_input( const tui::Terminal& terminal )
-{
- auto [width, height] = terminal.get_size();
- terminal.move_cursor( height, 1 );
- std::cout << "\x1b[2K\033[7m URL: \033[0m ";
- std::cout.flush();
-
- std::string input;
- terminal.show_cursor( true );
- while ( true ) {
- const char ch = terminal.read_key();
- if ( ch == '\r' || ch == '\n' ) {
- break;
- }
- if ( ch == 27 ) {
- input.clear();
- break;
- }
- if ( ch == 127 || ch == 8 ) {
- if ( !input.empty() ) {
- input.pop_back();
- std::cout << "\b \b";
- std::cout.flush();
- }
- } else if ( std::isprint( static_cast<unsigned char>( ch ) ) ) {
- input += ch;
- std::cout << ch;
- std::cout.flush();
- }
- }
- terminal.show_cursor( false );
-
- return Browser::format_url( std::move( input ) );
-}
-
-std::string get_terminal_input( const tui::Terminal& terminal, const std::string& prompt )
-{
- auto [width, height] = terminal.get_size();
- terminal.move_cursor( height, 1 );
- std::cout << "\x1b[2K\033[7m " << prompt << " \033[0m ";
- std::cout.flush();
-
- std::string input;
- terminal.show_cursor( true );
- while ( true ) {
- const char ch = terminal.read_key();
- if ( ch == '\r' || ch == '\n' ) {
- break;
- }
- if ( ch == 27 ) {
- input.clear();
- break;
- }
- if ( ch == 127 || ch == 8 ) {
- if ( !input.empty() ) {
- input.pop_back();
- std::cout << "\b \b";
- std::cout.flush();
- }
- } else if ( std::isprint( static_cast<unsigned char>( ch ) ) ) {
- input += ch;
- std::cout << ch;
- std::cout.flush();
- }
- }
- terminal.show_cursor( false );
- return input;
-}
-
-} // namespace ricochet::core
diff --git a/src/core/ui_view.cc b/src/core/ui_view.cc
deleted file mode 100644
index 5164fe0..0000000
--- a/src/core/ui_view.cc
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Ricochet - A minimalist CLI web browser for fast, distraction-free navigation.
- * Copyright (C) 2026 Richard Qin
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- */
-
-#include "ricochet/core/ui_view.hh"
-#include <iostream>
-
-namespace ricochet::core {
-
-std::string build_footer( std::string_view url, std::size_t width )
-{
- const std::string_view keys
- = " | [j/k]Scroll [n/N]Find [/]Nav [f]Hint [i]In [r]Ref [H/L]Back [h]Hist [b/B]Mark [?]Help [q]Quit ";
- const std::string_view prefix = " URL: ";
-
- std::string footer;
- if ( width <= keys.length() + prefix.length() + 3 ) {
- footer.reserve( prefix.length() + url.length() + keys.length() );
- footer += prefix;
- footer += url;
- footer += keys;
- if ( footer.length() > width && width > 3 ) {
- footer.erase( width - 3 );
- footer += "...";
- }
- } else {
- const std::size_t max_url_len = width - keys.length() - prefix.length();
- footer.reserve( width );
- footer += prefix;
- if ( url.length() > max_url_len ) {
- footer += url.substr( 0, max_url_len - 3 );
- footer += "...";
- } else {
- footer += url;
- }
- footer += keys;
- }
-
- if ( footer.length() < width ) {
- footer.append( width - footer.length(), ' ' );
- }
- return footer;
-}
-
-void draw_view( const tui::Terminal& terminal,
- const std::vector<std::string>& lines,
- std::size_t scroll_y,
- std::string_view url, // NOLINT(bugprone-easily-swappable-parameters)
- std::string_view title ) // NOLINT(bugprone-easily-swappable-parameters)
-{
- terminal.clear_screen();
- auto [width, height] = terminal.get_size();
- const std::size_t usable_height = ( height > 2 ) ? ( height - 2 ) : 1;
-
- std::string clean_title( title );
- if ( clean_title.empty() ) {
- const std::size_t start = url.find( "://" );
- const std::size_t host_start = ( start == std::string::npos ) ? 0 : start + 3;
- const std::size_t host_end = url.find( '/', host_start );
- clean_title = std::string( url.substr( host_start, host_end - host_start ) );
- }
- for ( char& c : clean_title ) {
- if ( c == '\n' || c == '\r' ) {
- c = ' ';
- }
- }
-
- std::string header = " PAGE: " + clean_title;
- if ( header.size() < width ) {
- header.append( width - header.size(), ' ' );
- } else if ( header.size() > width && width > 3 ) {
- header = header.substr( 0, width - 3 ) + "...";
- }
- std::cout << "\033[7m" << header << "\033[0m\r\n";
-
- for ( std::size_t i = 0; i < usable_height; ++i ) {
- if ( scroll_y + i < lines.size() ) {
- std::cout << lines[scroll_y + i] << "\r\n";
- } else {
- std::cout << "~\r\n";
- }
- }
-
- const std::string footer = build_footer( url, width );
- std::cout << "\033[7m" << footer << "\033[0m";
- std::cout.flush();
-}
-
-} // namespace ricochet::core
diff --git a/src/core/utils.cc b/src/core/utils.cc
index ddc6321..a410c8a 100644
--- a/src/core/utils.cc
+++ b/src/core/utils.cc
@@ -82,37 +82,4 @@ std::string strip_ddg_tracker( std::string target )
return target;
}
-std::vector<std::string> wrap_lines( const std::vector<std::string>& original_lines, std::size_t wrap_width )
-{
- std::vector<std::string> wrapped_lines;
- for ( const auto& line : original_lines ) {
- std::string current_line;
- std::size_t vis_count = 0;
- bool in_ansi = false;
- for ( const char c : line ) {
- if ( c == '\x1b' ) {
- in_ansi = true;
- }
- if ( in_ansi ) {
- current_line += c;
- if ( c == 'm' ) {
- in_ansi = false;
- }
- } else {
- if ( vis_count >= wrap_width ) {
- wrapped_lines.push_back( current_line + "\033[0m" );
- current_line.clear();
- vis_count = 0;
- }
- current_line += c;
- vis_count++;
- }
- }
- if ( !current_line.empty() || line.empty() ) {
- wrapped_lines.push_back( current_line + "\033[0m" );
- }
- }
- return wrapped_lines;
-}
-
} // namespace ricochet::core
diff --git a/src/tui/terminal.cc b/src/tui/terminal.cc
deleted file mode 100644
index 44c0f3b..0000000
--- a/src/tui/terminal.cc
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Ricochet - A minimalist CLI web browser for fast, distraction-free navigation.
- * Copyright (C) 2026 Richard Qin
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- */
-
-#include "ricochet/tui/terminal.hh"
-#include <cstdlib>
-#include <iostream>
-#include <sys/ioctl.h>
-#include <unistd.h>
-
-namespace ricochet::tui {
-
-Terminal::Terminal()
-{
- // get terminal attributes
- tcgetattr( STDIN_FILENO, &original_termios_ );
-
- struct termios raw = original_termios_;
-
- // close echo, close canonical mode
- // close terminal signals (ISIG disable Ctrl+C and Ctrl+Z, let the program handle it)
- raw.c_lflag &= ~( ECHO | ICANON | ISIG );
-
- // close software flow control (Ctrl+S, Ctrl+Q)
- raw.c_iflag &= ~( IXON | ICRNL );
-
- // apply new terminal attributes
- tcsetattr( STDIN_FILENO, TCSAFLUSH, &raw );
-}
-
-Terminal::~Terminal()
-{
- show_cursor( true );
- // RAII: restore terminal attributes when program exits
- tcsetattr( STDIN_FILENO, TCSAFLUSH, &original_termios_ );
-}
-
-char Terminal::read_key() const // NOLINT(readability-convert-member-functions-to-static)
-{
- char c = '\0';
- // read 1 byte
- if ( read( STDIN_FILENO, &c, 1 ) == -1 ) {
- return '\0';
- }
- return c;
-}
-
-void Terminal::clear_screen() const // NOLINT(readability-convert-member-functions-to-static)
-{
- // ANSI escape codes: \x1b[2J clear screen, \x1b[H move cursor to (1,1)
- std::cout << "\x1b[2J\x1b[H";
-}
-
-std::pair<std::size_t, std::size_t> Terminal::get_size() // NOLINT(readability-convert-member-functions-to-static)
- const
-{
- struct winsize w {};
- if ( ioctl( STDOUT_FILENO, TIOCGWINSZ, &w ) == -1 ) {
- return { 80, 24 };
- }
- return { static_cast<std::size_t>( w.ws_col ), static_cast<std::size_t>( w.ws_row ) };
-}
-
-void Terminal::move_cursor( std::size_t row, std::size_t col ) const // NOLINT
-{
- // ANSI: \x1b[H move to 1,1; \x1b[row;colH move to specified row and column
- std::cout << "\x1b[" << row << ";" << col << "H";
-}
-
-void Terminal::show_cursor( bool visible ) const // NOLINT
-{
- // \x1b[?25h show cursor, \x1b[?25l hide cursor
- std::cout << ( visible ? "\x1b[?25h" : "\x1b[?25l" );
-}
-
-} // namespace ricochet::tui \ No newline at end of file