use crate::{
buffer::{BufferOpenError, launch_file_argument, open_launch_buffer},
ecs::{
BufferPlugin, EditorCorePlugin, FocusPlugin, InitialEditorBuffer, LayoutPlugin,
TextShapePlugin,
},
features::{
ui::{ChromeStatusLine, UiFeaturePlugin},
vim::{VimFeaturePlugin, VimInputState},
},
fs_utils::FilesystemConfig,
render::TextRenderPlugin,
scene::EditorViewPlugin,
vim::VimConfig,
};
use bevy::{
input::{ButtonInput, keyboard::KeyboardInput},
prelude::{App, DefaultPlugins, KeyCode, MinimalPlugins, Plugin},
};
use haalka::prelude::HaalkaPlugin;
use std::env;
const INITIAL_TEXT_STREAM: &str = include_str!("../lib.rs");
#[derive(Clone, Copy, Debug, Default)]
struct EditorDataflowPlugins;
impl Plugin for EditorDataflowPlugins {
fn build(&self, app: &mut App) {
let _app = app
.add_plugins(EditorCorePlugin)
.add_plugins(BufferPlugin)
.add_plugins(FocusPlugin)
.add_plugins(LayoutPlugin)
.add_plugins(TextShapePlugin)
.add_plugins(VimFeaturePlugin);
}
}
#[derive(Clone, Copy, Debug, Default)]
struct EditorPresentationPlugins;
impl Plugin for EditorPresentationPlugins {
fn build(&self, app: &mut App) {
let _app = app
.add_plugins(HaalkaPlugin::new())
.add_plugins(EditorViewPlugin)
.add_plugins(TextRenderPlugin)
.add_plugins(UiFeaturePlugin);
}
}
pub fn run() -> Result<(), BufferOpenError> {
if env::var_os("ALMA_HEADLESS").is_some() {
return run_headless();
}
let _exit = build_windowed_app()?.run();
Ok(())
}
pub fn run_headless() -> Result<(), BufferOpenError> {
let update_count = env::var("ALMA_HEADLESS_UPDATES")
.ok()
.and_then(|value| value.parse::<usize>().ok())
.unwrap_or(1);
let mut app = build_headless_app()?;
for _update in 0..update_count {
app.update();
}
Ok(())
}
fn build_windowed_app() -> Result<App, BufferOpenError> {
let filesystem_config = FilesystemConfig::default();
let (text_stream, buffer_file) = open_launch_buffer(
launch_file_argument(env::args_os().skip(1)),
INITIAL_TEXT_STREAM,
&filesystem_config,
)?;
let mut app = App::new();
let _app = app
.insert_resource(filesystem_config)
.insert_resource(InitialEditorBuffer {
stream: text_stream,
file: buffer_file,
})
.insert_resource(VimConfig::default())
.insert_resource(VimInputState::default())
.insert_resource(ChromeStatusLine::default())
.add_plugins(DefaultPlugins)
.add_plugins(EditorDataflowPlugins)
.add_plugins(EditorPresentationPlugins);
Ok(app)
}
fn build_headless_app() -> Result<App, BufferOpenError> {
let filesystem_config = FilesystemConfig::default();
let (text_stream, buffer_file) = open_launch_buffer(
launch_file_argument(env::args_os().skip(1)),
INITIAL_TEXT_STREAM,
&filesystem_config,
)?;
let mut app = App::new();
let _app = app
.insert_resource(filesystem_config)
.insert_resource(InitialEditorBuffer {
stream: text_stream,
file: buffer_file,
})
.insert_resource(VimConfig::default())
.insert_resource(VimInputState::default())
.insert_resource(ChromeStatusLine::default())
.init_resource::<ButtonInput<KeyCode>>()
.add_message::<KeyboardInput>()
.add_plugins(MinimalPlugins)
.add_plugins(EditorDataflowPlugins);
Ok(app)
}
#[cfg(test)]
mod tests {
use super::build_headless_app;
use crate::ecs::components::buffer::EditorBuffer;
use bevy::prelude::{Entity, With};
#[test]
fn headless_app_starts_editor_dataflow_without_windowing() {
let mut app = build_headless_app().expect("headless app should build");
app.update();
let mut query = app
.world_mut()
.query_filtered::<Entity, With<EditorBuffer>>();
let buffers = query.iter(app.world()).collect::<Vec<_>>();
assert_eq!(buffers.len(), 1);
}
}