Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/dev2forge/bridgex/llms.txt

Use this file to discover all available pages before exploring further.

Bridgex is a single-binary Rust application compiled from the bridgex crate (version 0.2.1). The codebase is intentionally small and modular: each concern lives in its own module, there is no shared global mutable state outside of Freya’s reactive primitives, and the conversion pipeline is a straightforward function call chain. This page describes how the modules fit together, what each key dependency provides, how a file travels from disk to rendered Markdown, and how the release binary is optimised.

Module layout

The source tree under src/ is divided into five top-level modules, each with a clear single responsibility:

app

The root application component. Contains app(), which owns all top-level use_state hooks, initialises the theme, wires together the menu bar and popups, drives the editor, and registers the global keyboard handler.

logic

Houses converter.rs and the single public function convert_from_path(). This is the only place in the codebase that calls into Markitdown-rs; all LLM orchestration for JPEG images also happens here.

theme

Declares the GITHUB_COLORS constant (ColorsSheet), github_app_theme() (returns a Freya Theme), and github_editor_theme() (returns an EditorTheme for the code editor). No mutable state.

ui

Contains the individual UI components: menu (menu bar and open_file() dialog helper), llm (LLM API Key popup), about (About popup), licenses (Licenses popup), and popup (shared popup primitives).

utils

A collection of utility modules:
  • filesFileOwn (path wrapper), Filter (dialog filter type), and dialog helper functions (open_file_dialog, save_file_dialog, write_text_file).
  • llm_configLLMConfig struct with load() and save() for JSON persistence.
  • constantsDOCUMENT_EXTENSIONS (["pdf", "docx"]) and MENU_HEIGHT (30.0 px).
  • helpersopen_url() wrapper around webbrowser::open.

Key dependencies

The full dependency set is declared in Cargo.toml. The table below covers the dependencies that directly shape the application’s architecture:
CrateVersionRole
freya=0.4.0-rc.19UI framework (renderer, layout, reactive state, widgets). Enabled features: markdown, code-editor, skia-engine.
markitdown0.1.11File-to-Markdown conversion library. Provides MarkItDown, ConversionOptions, and llm::get_llm_description().
rfd0.17.2Native file dialogs (open and save) via the system file picker.
tokio1.0Async runtime. Used to block_on the async LLM description call inside the synchronous conversion function. Features: rt, rt-multi-thread, macros.
serde + serde_json1.0Serialisation and deserialisation of LLMConfig to and from llm_settings.json.
webbrowser1.2.1Opens URLs (e.g., repository links in the About popup) in the system default browser.
The freya pin uses an exact version (=0.4.0-rc.19) to prevent accidental upgrades to incompatible release candidates. When upgrading Freya, update this pin explicitly and retest the full UI.

File conversion pipeline

The journey from user action to rendered Markdown follows a linear path with no background threads involved except for the optional LLM image-description call:
1

User picks a file

The user clicks File → Open or presses Ctrl+O / ⌘+O. This calls open_file() in menu.rs, which builds a Vec<Filter> and delegates to FileOwn::open_file_dialog() (wrapping rfd). The result is an Option<FileOwn> containing the selected path.
2

State update triggers a re-render

open_file() returns Some(FileOwn), which is written into the open_file_state: State<Option<FileOwn>> hook in app(). Freya schedules a re-render.
3

Conversion is triggered

At the top of the next render pass, app() reads open_file_state. If it holds Some(file), it immediately calls:
crate::logic::converter::convert_from_path(
    file_path,
    Some(llm_api_key.read().clone()),
    Some(llm_client.read().clone()),
    Some(llm_model.read().clone()),
)
4

Markitdown-rs converts the file

Inside convert_from_path(), a MarkItDown::new() instance is created and .convert(filename, Some(options)) is called with a ConversionOptions struct that carries the normalised file extension, and optionally the LLM client and model strings.
5

LLM image description (JPEG only)

If the file extension is .jpg (.jpeg is normalised to .jpg in code), and all three LLM fields are non-empty, converter.rs sets the appropriate provider environment variable and calls llm::get_llm_description() using a single-threaded tokio runtime built with Builder::new_current_thread().enable_all().build(). The description is appended under a # Description: heading.
6

Editor state is updated

The returned String is written into the CodeEditorData rope:
editor.write().rope = Rope::from_str(converted.as_str());
editor.write().parse();
open_file_state is reset to None to prevent re-conversion on the next render.
7

Markdown preview re-renders

The MarkdownViewer component in the right panel reads the rope content reactively and re-renders the formatted preview. The left panel’s CodeEditor reflects the raw Markdown source.

UI state management

Bridgex uses Freya’s use_state hook for all mutable runtime state. There is no global singleton, no Arc<Mutex<...>>, and no message-passing channel. All state lives inside the single app() component and is passed into child components by cloning the State<T> handle (which is reference-counted internally by Freya).
State variableTypePurpose
open_file_stateState<Option<FileOwn>>Carries the path of a newly selected file; reset to None after conversion.
save_requestedState<bool>Flag set by menu/shortcut; cleared after the save dialog completes.
exit_requestedState<bool>Flag set by menu/shortcut; triggers std::process::exit(0).
current_file_pathState<Option<PathBuf>>Tracks the active file path, used as the default filename in the save dialog.
editorState<CodeEditorData>The rope-based editor state including parsed syntax and cursor.
llm_api_keyState<String>Loaded from LLMConfig at startup; bound to the LLM settings popup.
llm_clientState<String>Provider identifier; one of openai, gemini, deepseek, or empty.
llm_modelState<String>Model name string passed to Markitdown-rs.
show_aboutState<bool>Controls visibility of the About popup.
show_licensesState<bool>Controls visibility of the Licenses popup.
show_llm_settingsState<bool>Controls visibility of the LLM Settings popup.
Popup visibility is owned inside the respective popup structs (AboutPopup, LicencesPopup, LLMApiKeyPopup) and exposed as public State<bool> fields. app() clones those handles so that both the menu bar and the keyboard handler can toggle the same piece of state.

Release build profile

The [profile.release] section in Cargo.toml applies aggressive size and speed optimisations:
[profile.release]
codegen-units = 1
lto = true
opt-level = "z"
panic = "unwind"
strip = true
debug = false
overflow-checks = false
debug-assertions = false
incremental = false
SettingValueEffect
ltotrueLink-time optimisation across all crate boundaries, enabling cross-crate inlining and dead-code elimination.
opt-level"z"Optimise for minimum binary size rather than maximum speed.
striptrueRemove all debug symbols from the final binary.
codegen-units1Single codegen unit allows LLVM to optimise the entire crate as one unit, improving LTO effectiveness.
panic"unwind"Uses stack unwinding on panic, preserving the ability to catch panics at crate boundaries if needed.
incrementalfalseDisabled in release to avoid incremental-compilation artefacts in the distributed binary.
During development, use cargo run (which uses the [profile.dev] profile with incremental = true and opt-level = 0) for fast recompilation. Reserve cargo build --release for distribution builds.

Contributing: where to make changes

Add a new file format

Add a Filter::new(...) entry in open_file() (src/ui/menu.rs) and verify that Markitdown-rs supports the new extension. No changes to converter.rs are needed unless the format requires special pre-processing.

Add a new LLM provider

Add a new match arm in converter.rs for the environment variable, and extend the llm_client validation if needed. Update the LLM Settings popup in src/ui/llm.rs to expose the new provider string.

Change the theme

Edit GITHUB_COLORS in src/theme.rs. All UI components reference this constant or the derived github_app_theme() / github_editor_theme() functions, so a single edit propagates everywhere.

Add a new keyboard shortcut

Add a new Code::Key* arm inside the on_global_key_down handler in src/app.rs, mirroring the pattern used by the existing six shortcuts.

Build docs developers (and LLMs) love