···11-let run env app_name config =
22- let xdg = Xdge.Cmd.of_t env#fs app_name config in
11+let run (xdg,cfg) =
32 Fmt.pr
43 "%a@.%a@.@.%a@.%a@."
54 Fmt.(styled `Bold string)
65 "=== Cmdliner Config ==="
76 Xdge.Cmd.pp
88- config
77+ cfg
98 Fmt.(styled `Bold string)
109 "=== XDG Directories ==="
1110 (Xdge.pp ~brief:false ~sources:true)
1211 xdg
1313-;;
14121515-let main app_name config = Eio_main.run @@ fun env -> run env app_name config
1313+open Cmdliner
16141715let () =
1816 Fmt.set_style_renderer Fmt.stdout `Ansi_tty;
1917 let app_name = "xdg_example" in
2018 let doc = "Example program demonstrating XDG directory selection with Cmdliner" in
2119 let man =
2222- [ `S Cmdliner.Manpage.s_description
2020+ [ `S Manpage.s_description
2321 ; `P
2422 "This example shows how to use the Xdge library with Cmdliner to handle XDG Base \
2523 Directory Specification paths with command-line and environment variable \
2624 overrides."
2727- ; `S Cmdliner.Manpage.s_environment
2525+ ; `S Manpage.s_environment
2826 ; `P (Xdge.Cmd.env_docs app_name)
2927 ]
3028 in
3129 let info = Cmdliner.Cmd.info "xdg_example" ~version:"1.0" ~doc ~man in
3232- let term =
3333- let open Cmdliner.Term.Syntax in
3434- let+ config = Xdge.Cmd.term app_name in
3535- main app_name config
3636- in
3737- let cmd = Cmdliner.Cmd.v info term in
3030+ Eio_main.run @@ fun env ->
3131+ let create_xdg_term = Xdge.Cmd.term app_name env#fs in
3232+ let main_term = Term.(const run $ create_xdg_term) in
3333+ let cmd = Cmdliner.Cmd.v info main_term in
3834 exit @@ Cmdliner.Cmd.eval cmd
3935;;
+73-76
xdg-eio/lib/xdge.ml
···285285 ; runtime_dir : string with_source
286286 }
287287288288- let term app_name =
288288+ let term app_name fs =
289289 let open Cmdliner in
290290 let app_upper = String.uppercase_ascii app_name in
291291 let make_dir_arg name env_suffix xdg_var default_path =
···322322 | None -> { value = None; source = Default })))
323323 $ arg)
324324 in
325325- let home_prefix = "~" in
325325+ let home_prefix = "\\$HOME" in
326326 let config_dir =
327327 make_dir_arg
328328 "config"
···353353 in
354354 let runtime_dir = make_dir_arg "runtime" "RUNTIME_DIR" "XDG_RUNTIME_DIR" None in
355355 Term.(
356356- const (fun config_dir data_dir cache_dir state_dir runtime_dir ->
357357- { config_dir; data_dir; cache_dir; state_dir; runtime_dir })
356356+ const (fun config_dir_ws data_dir_ws cache_dir_ws state_dir_ws runtime_dir_ws ->
357357+ let config = { config_dir = config_dir_ws; data_dir = data_dir_ws; cache_dir = cache_dir_ws; state_dir = state_dir_ws; runtime_dir = runtime_dir_ws } in
358358+ let home_path = get_home_dir fs in
359359+ let xdg_ctx = Xdg.create ~env:Sys.getenv_opt () in
360360+ (* Helper to resolve directory from config with source tracking *)
361361+ let resolve_from_config config_ws xdg_getter =
362362+ match config_ws.value with
363363+ | Some dir -> resolve_path fs home_path dir, config_ws.source
364364+ | None ->
365365+ let xdg_base = xdg_getter xdg_ctx in
366366+ Eio.Path.(fs / xdg_base / app_name), config_ws.source
367367+ in
368368+ (* User directories *)
369369+ let config_dir, config_dir_source =
370370+ resolve_from_config config.config_dir Xdg.config_dir
371371+ in
372372+ let data_dir, data_dir_source = resolve_from_config config.data_dir Xdg.data_dir in
373373+ let cache_dir, cache_dir_source =
374374+ resolve_from_config config.cache_dir Xdg.cache_dir
375375+ in
376376+ let state_dir, state_dir_source =
377377+ resolve_from_config config.state_dir Xdg.state_dir
378378+ in
379379+ (* Runtime directory *)
380380+ let runtime_dir, runtime_dir_source =
381381+ match config.runtime_dir.value with
382382+ | Some dir -> Some (resolve_path fs home_path dir), config.runtime_dir.source
383383+ | None ->
384384+ ( Option.map
385385+ (fun base -> Eio.Path.(fs / base / app_name))
386386+ (Xdg.runtime_dir xdg_ctx)
387387+ , config.runtime_dir.source )
388388+ in
389389+ (* System directories - reuse shared helper *)
390390+ let config_dirs =
391391+ resolve_system_dirs
392392+ fs
393393+ home_path
394394+ app_name
395395+ "CONFIG_DIRS"
396396+ "XDG_CONFIG_DIRS"
397397+ [ "/etc/xdg" ]
398398+ in
399399+ let data_dirs =
400400+ resolve_system_dirs
401401+ fs
402402+ home_path
403403+ app_name
404404+ "DATA_DIRS"
405405+ "XDG_DATA_DIRS"
406406+ [ "/usr/local/share"; "/usr/share" ]
407407+ in
408408+ ensure_dir config_dir;
409409+ ensure_dir data_dir;
410410+ ensure_dir cache_dir;
411411+ ensure_dir state_dir;
412412+ Option.iter ensure_dir runtime_dir;
413413+ { app_name
414414+ ; config_dir
415415+ ; config_dir_source
416416+ ; data_dir
417417+ ; data_dir_source
418418+ ; cache_dir
419419+ ; cache_dir_source
420420+ ; state_dir
421421+ ; state_dir_source
422422+ ; runtime_dir
423423+ ; runtime_dir_source
424424+ ; config_dirs
425425+ ; data_dirs
426426+ }, config)
358427 $ config_dir
359428 $ data_dir
360429 $ cache_dir
···362431 $ runtime_dir)
363432 ;;
364433365365- let of_t fs app_name config =
366366- let fs = fs in
367367- let home_path = get_home_dir fs in
368368- let xdg_ctx = Xdg.create ~env:Sys.getenv_opt () in
369369- (* Helper to resolve directory from config with source tracking *)
370370- let resolve_from_config config_ws xdg_getter =
371371- match config_ws.value with
372372- | Some dir -> resolve_path fs home_path dir, config_ws.source
373373- | None ->
374374- let xdg_base = xdg_getter xdg_ctx in
375375- Eio.Path.(fs / xdg_base / app_name), config_ws.source
376376- in
377377- (* User directories *)
378378- let config_dir, config_dir_source =
379379- resolve_from_config config.config_dir Xdg.config_dir
380380- in
381381- let data_dir, data_dir_source = resolve_from_config config.data_dir Xdg.data_dir in
382382- let cache_dir, cache_dir_source =
383383- resolve_from_config config.cache_dir Xdg.cache_dir
384384- in
385385- let state_dir, state_dir_source =
386386- resolve_from_config config.state_dir Xdg.state_dir
387387- in
388388- (* Runtime directory *)
389389- let runtime_dir, runtime_dir_source =
390390- match config.runtime_dir.value with
391391- | Some dir -> Some (resolve_path fs home_path dir), config.runtime_dir.source
392392- | None ->
393393- ( Option.map
394394- (fun base -> Eio.Path.(fs / base / app_name))
395395- (Xdg.runtime_dir xdg_ctx)
396396- , config.runtime_dir.source )
397397- in
398398- (* System directories - reuse shared helper *)
399399- let config_dirs =
400400- resolve_system_dirs
401401- fs
402402- home_path
403403- app_name
404404- "CONFIG_DIRS"
405405- "XDG_CONFIG_DIRS"
406406- [ "/etc/xdg" ]
407407- in
408408- let data_dirs =
409409- resolve_system_dirs
410410- fs
411411- home_path
412412- app_name
413413- "DATA_DIRS"
414414- "XDG_DATA_DIRS"
415415- [ "/usr/local/share"; "/usr/share" ]
416416- in
417417- ensure_dir config_dir;
418418- ensure_dir data_dir;
419419- ensure_dir cache_dir;
420420- ensure_dir state_dir;
421421- Option.iter ensure_dir runtime_dir;
422422- { app_name
423423- ; config_dir
424424- ; config_dir_source
425425- ; data_dir
426426- ; data_dir_source
427427- ; cache_dir
428428- ; cache_dir_source
429429- ; state_dir
430430- ; state_dir_source
431431- ; runtime_dir
432432- ; runtime_dir_source
433433- ; config_dirs
434434- ; data_dirs
435435- }
436436- ;;
437434438435 let env_docs app_name =
439436 let app_upper = String.uppercase_ascii app_name in
+12-51
xdg-eio/lib/xdge.mli
···349349 ]} *)
350350val pp : ?brief:bool -> ?sources:bool -> Format.formatter -> t -> unit
351351352352-(** The source of a configuration value, indicating how it was determined.
353353-354354- This type tracks the provenance of directory paths, which is useful for
355355- debugging configuration issues and understanding which settings are in effect. *)
356356-type source =
357357- | Default (** XDG specification default value was used *)
358358- | Env of string (** Set via environment variable (includes variable name) *)
359359- | Cmdline (** Set via command-line argument *)
360360-361352(** {1 Cmdliner Integration} *)
362353363354module Cmd : sig
···375366 - Source tracking for debugging configuration issues
376367 - Pretty printing of configuration for --help output *)
377368378378- (** A configuration value paired with information about its source.
379379-380380- This type tracks both the value (if any) and where it came from,
381381- which is useful for debugging configuration issues. *)
382382- type 'a with_source =
383383- { value : 'a option (** The configuration value, if set *)
384384- ; source : source (** Where the value came from *)
385385- }
386386-387369 (** Complete XDG configuration gathered from command-line and environment.
388370389389- This record contains all XDG directory paths along with their sources,
371371+ This contains all XDG directory paths along with their sources,
390372 as determined by command-line arguments and environment variables. *)
391391- type t =
392392- { config_dir : string with_source (** Configuration directory path and source *)
393393- ; data_dir : string with_source (** Data directory path and source *)
394394- ; cache_dir : string with_source (** Cache directory path and source *)
395395- ; state_dir : string with_source (** State directory path and source *)
396396- ; runtime_dir : string with_source (** Runtime directory path and source *)
397397- }
373373+ type t
398374399399- (** [term app_name] creates a Cmdliner term for XDG directory configuration.
375375+ (** [term app_name fs] creates a Cmdliner term for XDG directory configuration.
400376401377 This function generates a Cmdliner term that handles all XDG directory
402402- configuration through both command-line flags and environment variables.
378378+ configuration through both command-line flags and environment variables,
379379+ and directly returns the XDG context.
403380404381 @param app_name The application name (used for environment variable prefixes)
382382+ @param fs The Eio filesystem to use for path resolution
405383406384 {b Generated Command-line Flags:}
407385 - [--config-dir DIR]: Override configuration directory
···420398 {b Example:}
421399 {[
422400 let open Cmdliner in
423423- let xdg_config = Cmd.term "myapp" in
424424- let main_term = Term.(const main $ xdg_config $ other_args) in
401401+ let main xdg =
402402+ (* use xdg directly *)
403403+ in
404404+ let xdg_term = Cmd.term "myapp" env#fs in
405405+ let main_term = Term.(const main $ xdg_term $ other_args) in
425406 (* ... *)
426407 ]} *)
427427- val term : string -> t Cmdliner.Term.t
428428-429429- (** [of_t fs app_name config] creates an XDG context from Cmdliner configuration.
430430-431431- This function takes the configuration gathered by {!term} and creates
432432- a fully initialized XDG context with all directories properly resolved
433433- and created.
434434-435435- @param fs The Eio filesystem providing filesystem access
436436- @param app_name The application name (must match the one used in {!term})
437437- @param config The configuration returned by evaluating {!term}
438438- @return A fully initialized XDG context
439439-440440- {b Example:}
441441- {[
442442- let main env xdg_config =
443443- let xdg = Xdg_eio.Cmd.of_t env#fs "myapp" xdg_config in
444444- (* Use xdg for application logic *)
445445- ...
446446- ]} *)
447447- val of_t : Eio.Fs.dir_ty Eio.Path.t -> string -> t -> xdg_t
408408+ val term : string -> Eio.Fs.dir_ty Eio.Path.t -> (xdg_t * t) Cmdliner.Term.t
448409449410 (** [env_docs app_name] generates documentation for environment variables.
450411
+1-1
xdg-eio/test/xdg.t
···319319 --cache-dir=DIR
320320 Override cache directory. Can also be set with
321321 XDG_EXAMPLE_CACHE_DIR or XDG_CACHE_HOME. Default:
322322- ~/.cache/xdg_example
322322+ $HOME/.cache/xdg_example
323323324324 --config-dir=DIR
325325 Override config directory. Can also be set with