Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Project Structure

A guided tour of the Two-Face codebase.

Directory Layout

two-face/
├── Cargo.toml           # Project manifest
├── Cargo.lock           # Dependency lock file
├── CLAUDE.md            # Development notes
├── README.md            # Project readme
│
├── src/
│   ├── main.rs          # Entry point
│   ├── lib.rs           # Library root (if applicable)
│   ├── config.rs        # Configuration loading
│   ├── parser.rs        # XML protocol parser
│   ├── network.rs       # Network connections
│   │
│   ├── core/            # Core business logic
│   │   ├── mod.rs
│   │   ├── app_core/    # Application state
│   │   │   ├── mod.rs
│   │   │   ├── state.rs
│   │   │   └── layout.rs
│   │   └── menu_actions.rs
│   │
│   ├── data/            # Data models
│   │   ├── mod.rs
│   │   └── widget.rs    # Widget data structures
│   │
│   └── frontend/        # User interface
│       └── tui/         # Terminal UI
│           ├── mod.rs
│           ├── input.rs
│           ├── input_handlers.rs
│           ├── command_input.rs
│           ├── text_window.rs
│           ├── tabbed_text_window.rs
│           ├── search.rs
│           ├── sync.rs
│           ├── menu_actions.rs
│           └── window_editor.rs
│
├── book/                # mdbook documentation
│   ├── book.toml
│   └── src/
│       └── *.md
│
├── tests/               # Integration tests
│   └── *.rs
│
└── docs/                # Additional documentation

Module Organization

Three-Layer Architecture

┌─────────────────────────────────────────────────────────────┐
│                    src/frontend/tui/                        │
│                                                             │
│    Terminal rendering, input handling, visual themes        │
│    Knows about: core, data                                  │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                        src/core/                            │
│                                                             │
│    Application state, business logic, event processing      │
│    Knows about: data                                        │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                        src/data/                            │
│                                                             │
│    Data models, parsing, serialization                      │
│    Knows about: nothing (foundation layer)                  │
└─────────────────────────────────────────────────────────────┘

Import rule: Upper layers can import lower layers, not vice versa.

Key Files

Entry Point: src/main.rs

// Typical structure
fn main() {
    // Parse command line arguments
    let args = Args::parse();

    // Load configuration
    let config = Config::load(&args)?;

    // Initialize application
    let app = App::new(config)?;

    // Run main loop
    app.run()?;
}

Responsibilities:

  • CLI argument parsing
  • Configuration loading
  • Application initialization
  • Main event loop

Configuration: src/config.rs

#![allow(unused)]
fn main() {
// Configuration structures
pub struct Config {
    pub connection: ConnectionConfig,
    pub layout: LayoutConfig,
    pub colors: ColorConfig,
    pub keybinds: KeybindConfig,
    // ...
}

impl Config {
    pub fn load(path: &Path) -> Result<Self> { ... }
    pub fn save(&self, path: &Path) -> Result<()> { ... }
}
}

Responsibilities:

  • TOML parsing
  • Default values
  • Validation
  • Serialization

Parser: src/parser.rs

#![allow(unused)]
fn main() {
// XML protocol parsing
pub enum ParsedElement {
    Text(String),
    RoomName(String),
    RoomDesc(String),
    Prompt(PromptData),
    Vitals(VitalsData),
    // Many more variants...
}

pub struct Parser {
    // Parser state
}

impl Parser {
    pub fn parse(&mut self, input: &str) -> Vec<ParsedElement> { ... }
}
}

Responsibilities:

  • XML tag recognition
  • State machine parsing
  • Element extraction
  • Stream identification

Network: src/network.rs

#![allow(unused)]
fn main() {
// Connection handling
pub enum ConnectionMode {
    Lich { host: String, port: u16 },
    Direct { account: String, ... },
}

pub struct Connection {
    mode: ConnectionMode,
    stream: TcpStream,
}

impl Connection {
    pub fn connect(mode: ConnectionMode) -> Result<Self> { ... }
    pub fn send(&mut self, data: &str) -> Result<()> { ... }
    pub fn receive(&mut self) -> Result<String> { ... }
}
}

Responsibilities:

  • Connection establishment
  • TLS handling (direct mode)
  • Data transmission
  • Reconnection logic

Widget Data: src/data/widget.rs

#![allow(unused)]
fn main() {
// Widget type definitions
pub enum WidgetType {
    Text,
    TabbedText,
    Progress,
    Compass,
    // ...
}

pub struct WidgetConfig {
    pub widget_type: WidgetType,
    pub name: String,
    pub x: u16,
    pub y: u16,
    pub width: u16,
    pub height: u16,
    // Type-specific config...
}
}

Responsibilities:

  • Widget type enumeration
  • Configuration structures
  • Layout data
  • Serialization traits

Application State: src/core/app_core/state.rs

#![allow(unused)]
fn main() {
// Application state management
pub struct AppState {
    pub vitals: Vitals,
    pub room: RoomInfo,
    pub inventory: Inventory,
    pub indicators: Indicators,
    // ...
    generation: u64,  // Change tracking
}

impl AppState {
    pub fn update(&mut self, element: ParsedElement) {
        // Update state based on parsed element
        self.generation += 1;
    }
}
}

Responsibilities:

  • Game state tracking
  • Update processing
  • Change notification
  • Generation counting

Layout: src/core/app_core/layout.rs

#![allow(unused)]
fn main() {
// Layout management
pub struct Layout {
    widgets: Vec<Widget>,
    focus_index: usize,
}

impl Layout {
    pub fn load(config: &LayoutConfig) -> Result<Self> { ... }
    pub fn render(&self, frame: &mut Frame) { ... }
    pub fn handle_input(&mut self, key: KeyEvent) { ... }
}
}

Responsibilities:

  • Widget arrangement
  • Focus management
  • Layout loading
  • Coordinate calculation

TUI Module: src/frontend/tui/mod.rs

#![allow(unused)]
fn main() {
// Terminal UI main module
pub struct Tui {
    terminal: Terminal<Backend>,
    layout: Layout,
    state: AppState,
}

impl Tui {
    pub fn new() -> Result<Self> { ... }
    pub fn run(&mut self) -> Result<()> { ... }
    pub fn render(&mut self) -> Result<()> { ... }
    pub fn handle_event(&mut self, event: Event) -> Result<()> { ... }
}
}

Responsibilities:

  • Terminal setup/teardown
  • Event loop
  • Rendering coordination
  • Input routing

Data Flow

Incoming Data

Network → Parser → State Update → Widget Sync → Render
   │         │           │              │           │
   │         │           │              │           └─ TUI draws frame
   │         │           │              └─ Widgets check generation
   │         │           └─ AppState updates, bumps generation
   │         └─ Raw XML → ParsedElements
   └─ TCP/TLS receives bytes

User Input

Terminal Event → TUI → Handler → Action → Effect
      │           │        │        │         │
      │           │        │        │         └─ State change or command send
      │           │        │        └─ Keybind lookup / macro expansion
      │           │        └─ Input type routing (key/mouse/resize)
      │           └─ Event loop captures
      └─ User presses key

Testing Structure

tests/
├── integration_test.rs   # Full application tests
├── parser_tests.rs       # Parser-specific tests
└── widget_tests.rs       # Widget rendering tests

src/
├── parser.rs
│   └── #[cfg(test)] mod tests { ... }  # Unit tests
└── config.rs
    └── #[cfg(test)] mod tests { ... }  # Unit tests

Configuration Files

User configuration (runtime):

~/.two-face/
├── config.toml
├── layout.toml
├── colors.toml
├── highlights.toml
├── keybinds.toml
├── triggers.toml
└── simu.pem

Documentation

book/                    # mdbook documentation (this!)
├── book.toml
└── src/
    ├── SUMMARY.md
    └── *.md

docs/                    # Additional docs
└── *.md

Build Artifacts

target/
├── debug/               # Debug build
│   └── two-face
├── release/             # Release build
│   └── two-face
└── doc/                 # Generated documentation
    └── two_face/

See Also