1
0
Fork 0
forked from wry/wry

cli: add config subcommand

This commit is contained in:
Julian Orth 2026-03-20 18:49:39 +01:00
parent 6727f3e4bc
commit 668188ff43
4 changed files with 119 additions and 4 deletions

View file

@ -37,6 +37,7 @@ Usage: jay [OPTIONS] <COMMAND>
Commands:
run Run the compositor
config Create/modify the toml config
generate-completion Generate shell completion scripts for jay
log Open the log file
set-log-level Sets the log level
@ -45,6 +46,7 @@ Commands:
screenshot Take a screenshot
idle Inspect/modify the idle (screensaver) settings
run-privileged Run a privileged program
run-tagged Run a program with a connection tag
seat-test Tests the events produced by a seat
portal Run the desktop portal
randr Inspect/modify graphics card and connector settings
@ -53,10 +55,13 @@ Commands:
color-management Inspect/modify the color-management settings
clients Inspect/manipulate the connected clients
tree Inspect the surface tree
control-center Opens the control center
version Prints the Jay version and exits
pid Prints the Jay PID and exits
help Print this message or the help of the given subcommand(s)
Options:
--log-level <LOG_LEVEL> The log level [default: info] [possible values: trace, debug, info, warn, error]
--log-level <LOG_LEVEL> The log level [default: info] [possible values: trace, debug, info, warn, error, off]
-h, --help Print help
```

View file

@ -1,6 +1,7 @@
mod clients;
mod color;
mod color_management;
mod config;
mod control_center;
mod damage_tracking;
mod duration;
@ -25,7 +26,7 @@ mod xwayland;
use {
crate::{
cli::{
clients::ClientsArgs, color_management::ColorManagementArgs,
clients::ClientsArgs, color_management::ColorManagementArgs, config::ConfigArgs,
damage_tracking::DamageTrackingArgs, idle::IdleCmd, input::InputArgs, randr::RandrArgs,
reexec::ReexecArgs, run_tagged::RunTaggedArgs, tree::TreeArgs, xwayland::XwaylandArgs,
},
@ -58,6 +59,8 @@ pub struct GlobalArgs {
pub enum Cmd {
/// Run the compositor.
Run(RunArgs),
/// Create/modify the toml config.
Config(ConfigArgs),
/// Generate shell completion scripts for jay.
GenerateCompletion(GenerateArgs),
/// Open the log file.
@ -248,5 +251,6 @@ pub fn main() {
Cmd::RunTests => crate::it::run_tests(),
Cmd::Reexec(a) => reexec::main(cli.global, a),
Cmd::ControlCenter => control_center::main(cli.global),
Cmd::Config(a) => config::main(cli.global, a),
}
}

106
src/cli/config.rs Normal file
View file

@ -0,0 +1,106 @@
use {
crate::{cli::GlobalArgs, compositor::config_dir, logger::Logger, utils::errorfmt::ErrorFmt},
clap::{Args, Subcommand},
jay_toml_config::CONFIG_TOML,
std::path::Path,
uapi::{UstrPtr, c},
};
#[derive(Args, Debug)]
pub struct ConfigArgs {
#[clap(subcommand)]
pub command: ConfigCmd,
}
#[derive(Subcommand, Debug)]
pub enum ConfigCmd {
/// Initialize the toml config file.
Init(ConfigInitArgs),
/// Print the path to the config.
Path,
/// Open the config directory with xdg-open.
OpenDir,
}
#[derive(Args, Debug)]
pub struct ConfigInitArgs {
/// Overwrite an existing config.toml file.
///
/// The old file will be backed up to `config.toml.<n>`.
#[clap(long)]
overwrite: bool,
}
pub fn main(global: GlobalArgs, args: ConfigArgs) {
Logger::install_stderr(global.log_level);
let dir = || {
let Some(dir) = config_dir() else {
fatal!("Could not determine the config directory");
};
dir
};
match args.command {
ConfigCmd::Init(a) => {
let dir = dir();
if let Err(e) = std::fs::create_dir_all(&dir) {
fatal!("Could not create config directory: {}", ErrorFmt(e));
}
let toml_path = Path::new(&dir).join(CONFIG_TOML);
let mut write_real_path = toml_path.clone();
if matches!(std::fs::exists(&toml_path), Ok(true)) {
if !a.overwrite {
eprintln!("{} already exists", toml_path.display());
eprintln!("Pass --overwrite to overwrite the config file");
return;
}
for i in 1.. {
write_real_path = toml_path.with_added_extension(i.to_string());
if matches!(std::fs::exists(&write_real_path), Ok(false)) {
break;
}
}
}
let res = std::fs::write(&write_real_path, jay_toml_config::DEFAULT);
if let Err(e) = res {
fatal!("Could not write config: {}", ErrorFmt(e));
}
if write_real_path != toml_path {
let res = uapi::renameat2(
c::AT_FDCWD,
&*toml_path,
c::AT_FDCWD,
&*write_real_path,
c::RENAME_EXCHANGE,
);
if let Err(e) = res {
fatal!(
"Could not exchange {} and {}: {}",
toml_path.display(),
write_real_path.display(),
ErrorFmt(e),
);
}
eprintln!("Backed up old config.toml to {}", write_real_path.display());
}
eprintln!("Config written to {}", toml_path.display());
}
ConfigCmd::Path => {
let dir = dir();
let toml_path = Path::new(&dir).join(CONFIG_TOML);
println!("{}", toml_path.display());
}
ConfigCmd::OpenDir => {
const XDG_OPEN: &str = "xdg-open";
let dir = dir();
let mut args = UstrPtr::new();
args.push(XDG_OPEN);
args.push(&*dir);
if matches!(std::fs::exists(&dir), Ok(false)) {
fatal!("Use `jay config init` to initialize the config first");
}
if let Err(e) = uapi::execvp(XDG_OPEN, &args) {
fatal!("Could not start xdg-open: {}", ErrorFmt(e));
}
}
}
}

View file

@ -1298,7 +1298,7 @@ async fn watch_config(persistent: Rc<PersistentState>) {
}
}
const CONFIG_TOML: &str = "config.toml";
pub const CONFIG_TOML: &str = "config.toml";
fn load_config(initial_load: bool, auto_reload: bool, persistent: &Rc<PersistentState>) {
let mut path = PathBuf::from(config_dir());
@ -1675,7 +1675,7 @@ fn create_command(exec: &Exec) -> Command {
command
}
const DEFAULT: &[u8] = include_bytes!("default-config.toml");
pub const DEFAULT: &[u8] = include_bytes!("default-config.toml");
pub fn configure() {
let mark_names = Default::default();