Index: trunk/README.md
===================================================================
--- trunk/README.md	(revision 77)
+++ trunk/README.md	(revision 78)
@@ -3,4 +3,5 @@
 
 Homepage: https://suzunaan.yakumo.dev/kosuzu/
+Issue tracker: https://suzunaan.yakumo.dev/kosuzu/report/1
 
 ## Differences from Logarion
@@ -8,6 +9,2 @@
 * A `txt_init` program in the spirit of the old subcommand from years past
 * Due to the current maintainer's decision, this project isn't hosted on Git anymore (but there is a [mirror](https://git.yakumo.dev/yakumo.izuru/kosuzu) available)
-
-## To-do
-* Support [geomyidae](gopher://bitreich.org/1/scm/geomyidae) `.gph` indexes, for now those can be generated manually somewhat
-* Support tab-separated value gophermaps for any other gopher daemon
Index: trunk/cmd/txt/dune
===================================================================
--- trunk/cmd/txt/dune	(revision 77)
+++ trunk/cmd/txt/dune	(revision 78)
@@ -3,4 +3,4 @@
  (public_name txt)
  (modules txt authors convert conversion edit file index last listing
-  new topics html atom gemini peers pull recent unfile)
+  new topics html atom gemini peers publish pull recent unfile)
  (libraries text_parse.converter text_parse.parsers kosuzu msgpck curl str cmdliner))
Index: trunk/cmd/txt/publish.ml
===================================================================
--- trunk/cmd/txt/publish.ml	(revision 78)
+++ trunk/cmd/txt/publish.ml	(revision 78)
@@ -0,0 +1,73 @@
+let targets pubdir = List.fold_left
+	(fun a x ->
+		let path = Filename.concat pubdir (snd x) in
+		try if Sys.is_directory path then (fst x, path)::a else a with Sys_error _ -> a)
+	[]
+	["htm,atom", "public_html/"; "gmi,gmi-atom", "public_gemini/"; "", "public_gopher/"]
+
+let wizard () =
+	print_endline "No txt.conf found. It's required for the repository name & id. Create one? (y/N)";
+	match input_line stdin with
+	|"y"-> 
+		let title =
+			print_endline "Title for repository: ";
+			input_line stdin in
+		let authors =
+			print_endline "Authors (format: name <name@email> <http://website>): ";
+			input_line stdin in
+		Kosuzu.File_store.file "txt.conf"
+			(Printf.sprintf "Id: %s\nTitle: %s\nAuthors: %s\n" (Kosuzu.Id.generate ()) title authors);
+		Kosuzu.File_store.of_kv_file ()
+	| _ -> print_endline "Create a txt.conf and run publish again"; exit 1
+
+open Kosuzu
+let publish pubdir ids =
+	let kv =
+		match Kosuzu.File_store.of_kv_file ()
+		with x when x = Kosuzu.Store.KV.empty -> wizard () | x -> x in
+	let predicate t = List.mem t.Text.id ids in
+	let pubdir_source, pubdir = match pubdir with Some d -> "--pubdir ", d | None ->
+		try "txt.conf:Pubdir", Kosuzu.Store.KV.find "Pubdir" kv with Not_found ->
+		try "$TXTPUBDIR", Sys.getenv "TXTPUBDIR" with Not_found -> "$TXTPUBDIR", ""
+	in
+	let targets = targets pubdir in
+	if targets = [] then
+		Printf.eprintf "No target directories in %s='%s' (for example %s)\n"
+			pubdir_source pubdir (Filename.concat pubdir "public_html")
+	else begin
+		let pub_dirs = List.map (fun x -> snd x) targets in
+		File_store.iter ~predicate (fun (_t, p) ->
+			try File.file ((List.hd p)::pub_dirs)
+			with Unix.Unix_error (Unix.EEXIST, _, _) -> ());
+		List.iter (fun t -> Printf.eprintf "%s %s\n" (fst t) (snd t);
+			Index.((load (snd t)) false None None None None);
+			Convert.at_path (fst t) false (snd t))
+			targets
+	end
+
+open Cmdliner
+
+let ids = Arg.(value & pos_all string [] & info [] ~docv: "Text ID")
+let pubdir = Arg.(value & opt (some string) None & info ["p"; "pubdir"] ~docv: "Directory path" ~doc: "Set top directory for publishing files")
+let publish_t = Term.(const publish $ pubdir $ ids)
+
+let cmd =
+  let doc = "Convert texts into pubnix-style directories if they exist" in
+  let man = [
+      `S Manpage.s_description;
+      `P "This subcommand is meant for people who use this software in shared hosts such as SDF or Tildeverse";
+      `P "Currently supports conversion to public_gemini (.gmi), public_gopher (.txt), and public_html (.htm[l])";
+      `S Manpage.s_environment;
+      `P "TXTPUBDIR - Pubnix-style output directory" ]
+  in
+  let info = Cmd.info "publish" ~doc ~man in
+  Cmd.v info publish_t
+      
+(*
+let term =
+	let ids = Arg.(value & pos_all string [] & info [] ~docv:"text ids") in
+	let pubdir = Arg.(value & opt (some string) None & info ["p"; "pubdir"] ~docv:"directory path"
+		~doc:"set top directory for publishing files") in
+	let doc = "convert texts into standard public dirs pubdir/public_{html,gemini,gopher} if they exist" in
+	Term.(const publish $ pubdir $ ids), Term.info "publish" ~doc ~man:[ `S "DESCRIPTION"; `P doc ]
+ *)
Index: trunk/cmd/txt/txt.ml
===================================================================
--- trunk/cmd/txt/txt.ml	(revision 77)
+++ trunk/cmd/txt/txt.ml	(revision 78)
@@ -11,4 +11,5 @@
     New.cmd;
     Peers.cmd;
+    Publish.cmd;
     Pull.cmd;
     Recent.cmd;
@@ -29,5 +30,5 @@
       `P "https://en.touhouwiki.net/wiki/Forbidden_Scrollery" ]
   in
-  Cmd.group (Cmd.info "txt" ~version:"%%VERSION%%" ~doc ~man) ~default:default_cmd subs
+  Cmd.group (Cmd.info "txt" ~version:"1.4.5" ~doc ~man) ~default:default_cmd subs
 
 let main () = exit (Cmd.eval txt)
Index: trunk/cmd/txt_init/txt_init.ml
===================================================================
--- trunk/cmd/txt_init/txt_init.ml	(revision 77)
+++ trunk/cmd/txt_init/txt_init.ml	(revision 78)
@@ -1,18 +1,17 @@
-(* $Id$ *)
 let init_repo = 
-        print_endline "Initializing repository...";
-        print_endline "It's required for the repository name and id.";
-        print_endline "Create one? (y/n)";
-        match input_line stdin with
-        |"y"->
-                        let title =
-                                print_endline "Title for repository: ";
-                                input_line stdin in
-                        let authors =
-                                print_endline "Authors (format: name <name@email> <http://website>): ";
-                                input_line stdin in
-                        Kosuzu.File_store.file "txt.conf" 
-                        (Printf.sprintf "Id:%s\nTitle: %s\nAuthors: %s\n" (Kosuzu.Id.generate ()) title authors);
-                        Kosuzu.File_store.of_kv_file ()
-        | _ ->
-                        print_endline "Aborting..."; exit 1
+  print_endline "Initializing repository...";
+  print_endline "It's required for the repository name and id.";
+  print_endline "Create one? (y/n)";
+  match input_line stdin with
+  |"y"->
+    let title =
+      print_endline "Title for repository: ";
+      input_line stdin in
+    let authors =
+      print_endline "Authors (format: name <name@email> <http://website>): ";
+      input_line stdin in
+    Kosuzu.File_store.file "txt.conf" 
+      (Printf.sprintf "Id:%s\nTitle: %s\nAuthors: %s\n" (Kosuzu.Id.generate ()) title authors);
+    Kosuzu.File_store.of_kv_file ()
+  | _ ->
+     print_endline "Aborting..."; exit 1
Index: trunk/dune-project
===================================================================
--- trunk/dune-project	(revision 77)
+++ trunk/dune-project	(revision 78)
@@ -1,10 +1,10 @@
 (lang dune 2.0)
 (name kosuzu)
-(version 1.4.4)
+(version 1.4.5)
 (license EUPL-1.2)
 (authors "orbifx <fox@orbitalfox.eu>")
 (maintainers "Izuru Yakumo <eternal-servant@yakumo.dev>")
 (homepage "https://suzunaan.yakumo.dev/kosuzu/")
-(source (uri svn+https://svn.yakumo.dev/yakumo.izuru/kosuzu))
+(source (uri svn+https://svn.yakumo.dev/repo/kosuzu))
 
 (generate_opam_files true)
Index: trunk/kosuzu.opam
===================================================================
--- trunk/kosuzu.opam	(revision 77)
+++ trunk/kosuzu.opam	(revision 78)
@@ -22,3 +22,3 @@
   ]
 ]
-dev-repo: "svn+https://svn.yakumo.dev/yakumo.izuru/kosuzu"
+dev-repo: "svn+https://svn.yakumo.dev/repo/kosuzu"
