/*
* 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 .
*/
#pragma once
#include "ricochet/tui/input.hh"
#include "ricochet/tui/messages.hh"
#include
#include
#include
#include
#include
#include
namespace ricochet::tui {
namespace detail {
class Mailbox;
}
struct TerminalOptions
{
bool capture_mouse { true };
// Explicit host opt-in: terminfo does not establish bracketed-paste support.
bool bracketed_paste { false };
std::chrono::milliseconds escape_delay { 25 };
};
struct TerminalCapabilities
{
bool colors { false };
bool mouse_buttons { false };
bool mouse_motion { false };
bool bracketed_paste { false };
};
enum class PostResult : std::uint8_t
{
Queued,
Closed
};
// A sender can outlive the UI session. Posting is thread-safe; it never calls curses.
class UpdateSender
{
public:
PostResult post_update( HostUpdate update ) const;
private:
friend class Session;
explicit UpdateSender( std::shared_ptr mailbox );
std::shared_ptr mailbox_;
};
struct StepResult
{
bool running { true };
// Incremental document updates and editing are subsequent milestones. Until then,
// unsupported updates are returned intact rather than silently acknowledged.
std::vector unhandled_updates {};
std::optional terminal_closed {};
std::optional error {};
};
class Session
{
public:
explicit Session( TerminalOptions options = {} );
// Streams must remain open until destruction. Construction, step, close and
// destruction run on the same UI thread; only one terminal session may exist.
Session( std::FILE& input, std::FILE& output, TerminalOptions options = {} );
~Session();
Session( const Session& ) = delete;
Session& operator=( const Session& ) = delete;
Session( Session&& ) = delete;
Session& operator=( Session&& ) = delete;
UpdateSender sender() const;
PostResult post_update( HostUpdate update );
// max_wait bounds idle waiting. Decoding a partial terminal key sequence can
// additionally wait for escape_delay; processing batches is bounded separately.
StepResult step( std::chrono::milliseconds max_wait );
std::vector take_actions();
std::optional snapshot( TabId tab ) const;
TerminalCapabilities capabilities() const;
void close() noexcept;
private:
class Impl;
std::unique_ptr impl_;
};
} // namespace ricochet::tui