Compare commits

...

10 Commits

Author SHA1 Message Date
yakumo.izuru
10888bc8b6 Move documentation to Suzunaan software library, stop assuming txt.conf doesn't exist in txt_init
Signed-off-by: Izuru Yakumo <yakumo.izuru@chaotic.ninja>

git-svn-id: https://svn.yakumo.dev/yakumo.izuru/kosuzu/trunk@76 eb64cd80-c68d-6f47-b6a3-0ada418499da
2024-08-22 23:52:12 +00:00
yakumo.izuru
57304917a2 Remove text-parse submodule
Signed-off-by: Izuru Yakumo <yakumo.izuru@chaotic.ninja>

git-svn-id: https://svn.yakumo.dev/yakumo.izuru/kosuzu/trunk@75 eb64cd80-c68d-6f47-b6a3-0ada418499da
2024-08-22 19:36:29 +00:00
yakumo.izuru
4a93a47e50 Resize oversized picture
Signed-off-by: Izuru Yakumo <yakumo.izuru@chaotic.ninja>

git-svn-id: https://svn.yakumo.dev/yakumo.izuru/kosuzu/trunk@74 eb64cd80-c68d-6f47-b6a3-0ada418499da
2024-08-22 16:48:43 +00:00
yakumo.izuru
97e4d08503 Because sweet girls are the best, officially rebranding Logarion to Kosuzu
Signed-off-by: Izuru Yakumo <yakumo.izuru@chaotic.ninja>

git-svn-id: https://svn.yakumo.dev/yakumo.izuru/kosuzu/trunk@73 eb64cd80-c68d-6f47-b6a3-0ada418499da
2024-08-22 16:32:00 +00:00
yakumo.izuru
6e97efbf0c Reimplemented txt-init in OCaml
Signed-off-by: Izuru Yakumo <yakumo.izuru@chaotic.ninja>

git-svn-id: https://svn.yakumo.dev/yakumo.izuru/kosuzu/trunk@72 eb64cd80-c68d-6f47-b6a3-0ada418499da
2024-08-22 15:02:35 +00:00
yakumo.izuru
583f725b21 Add txt-init program
Signed-off-by: Izuru Yakumo <yakumo.izuru@chaotic.ninja>

git-svn-id: https://svn.yakumo.dev/yakumo.izuru/kosuzu/trunk@71 eb64cd80-c68d-6f47-b6a3-0ada418499da
2024-08-21 16:57:44 +00:00
yakumo.izuru
28ca660dab What is the point of --interactive if it throws you into a text editor, anyway?
Signed-off-by: Izuru Yakumo <yakumo.izuru@chaotic.ninja>

git-svn-id: https://svn.yakumo.dev/yakumo.izuru/kosuzu/trunk@70 eb64cd80-c68d-6f47-b6a3-0ada418499da
2024-08-21 13:31:58 +00:00
yakumo.izuru
521112d3d6 txt new no longer sets default titles, remove %%VERSION%% from all subcommands (as they're pulled from txt.ml)
Signed-off-by: Izuru Yakumo <yakumo.izuru@chaotic.ninja>

git-svn-id: https://svn.yakumo.dev/yakumo.izuru/kosuzu/trunk@69 eb64cd80-c68d-6f47-b6a3-0ada418499da
2024-08-21 11:14:12 +00:00
yakumo.izuru
6ad15ec7eb Update inline documentation
Signed-off-by: Izuru Yakumo <yakumo.izuru@chaotic.ninja>

git-svn-id: https://svn.yakumo.dev/yakumo.izuru/kosuzu/trunk@68 eb64cd80-c68d-6f47-b6a3-0ada418499da
2024-08-21 02:15:27 +00:00
yakumo.izuru
2f038028dc Remove the deprecated 'read' subcommand
Signed-off-by: Izuru Yakumo <yakumo.izuru@chaotic.ninja>

git-svn-id: https://svn.yakumo.dev/yakumo.izuru/kosuzu/trunk@67 eb64cd80-c68d-6f47-b6a3-0ada418499da
2024-08-21 01:51:19 +00:00
45 changed files with 199 additions and 415 deletions

1
.gitignore vendored
View File

@ -9,3 +9,4 @@
_build
*.htm
index.html
/.svn

3
.gitmodules vendored
View File

@ -1,3 +0,0 @@
[submodule "text-parse-ml"]
path = text-parse
url = https://git.chaotic.ninja/yakumo.izuru/text-parse-ml

View File

@ -1,6 +1,6 @@
OS=`uname -s`
MACHINE=`uname -m`
DATE=`date -r _build/default/cli/txt.exe +%Y%m%d`
DATE=`date -r _build/default/cmd/txt/txt.exe +%Y%m%d`
COMMIT=`git rev-parse --short HEAD`
PREFIX=/usr/local
@ -10,19 +10,22 @@ LD=cc
all:
@dune build
deps:
@opam install dune ocurl cmdliner=1.0.4 msgpck
cli:
@dune build cli/txt.exe
@opam install dune ocurl cmdliner msgpck
txt:
@dune build cmd/txt/txt.exe
clean:
@dune clean
dist:
@dune build
@cp _build/default/cli/txt.exe txt.exe
@cp _build/default/cmd/txt/txt.exe txt.exe
@strip txt.exe
@tar czvf "kosuzu-${OS}-${MACHINE}-${DATE}-${COMMIT}" txt.exe readme.txt
@rm txt.exe
txt_init:
@dune build cmd/txt_init/txt_init.exe
install:
@dune install --prefix ${PREFIX}
uninstall:
@dune uninstall --prefix ${PREFIX}
.PHONY: cli
.PHONY: txt txt_init

View File

@ -1,16 +1,5 @@
# Logarion
Text archival and exchange.
# Kosuzu
Text archival and exchange, named after [Kosuzu Motoori](https://en.touhouwiki.net/wiki/Kosuzu_Motoori) from [Forbidden Scrollery](https://en.touhouwiki.net/wiki/Forbidden_Scrollery).
## Contact
* [Mailing list](https://lists.tildeverse.org/postorius/lists/logarion.lists.tildeverse.org/)
## References
* [Building from source](https://logarion.chaotic.ninja/9egbae.htm)
* [Creating texts & publishing on the net](https://logarion.chaotic.ninja/hvhhwf.htm)
* [Exploring & pulling texts from Logarion repositories](https://logarion.chaotic.ninja/3sqd84.htm)
* [Header format](https://logarion.chaotic.ninja/d41e68.htm)
* [Txt uniform resource names](https://logarion.chaotic.ninja/h1a9tg.htm)
## Maintainers
* orbifx (original author, former maintainer)
* Izuru Yakumo (contributor, current maintainer)
* [Mailing list](mailto:kosuzu-dev@chaotic.ninja)

View File

@ -1,6 +0,0 @@
(executable
(name txt)
(public_name txt)
(modules txt authors convert conversion edit file index last listing
new topics html atom gemini peers pull read recent unfile)
(libraries text_parse.converter text_parse.parsers logarion msgpck curl str cmdliner ocmd))

View File

@ -1,24 +0,0 @@
open Logarion
open Cmdliner
let id = Arg.(value & pos 0 string "" & info [] ~docv:"text ID")
let recurse = Arg.(value & flag & info ["R"] ~doc:"recurse, include subdirs")
let reverse = Arg.(value & flag & info ["r"] ~doc:"reverse order")
let time = Arg.(value & flag & info ["t"] ~doc:"sort by time, newest first")
let number = Arg.(value & opt (some int) None & info ["n"] ~docv:"number" ~doc:"number of entries to list")
let authed = Arg.(value & opt (some string) None & info ["authored"] ~docv:"comma-separated names" ~doc:"texts by authors")
let topics = Arg.(value & opt (some string) None & info ["topics"] ~docv:"comma-separated topics" ~doc:"texts with topics")
let read_t = Term.(const (Archive.apply_sys_util "PAGER" "less") $ recurse $ time $ reverse $ number $ authed $ topics $ id)
let cmd =
let doc = "Read a text" in
let man = [
`S Manpage.s_description;
`P "Deprecated. This subcommand will be removed in a future release of Logarion";
`P "This invokes the PAGER utility ('less' if unset) on an article of the archive" ]
in
let info = Cmd.info "read" ~version:"%%VERSION%%" ~doc ~man in
Cmd.v info read_t

View File

@ -1,31 +0,0 @@
open Cmdliner
let subs = [
Authors.cmd; (* Done *)
Convert.cmd; (* Done *)
Edit.cmd; (* Done *)
File.cmd; (* Done *)
Index.cmd; (* Done *)
Last.cmd; (* Done *)
Listing.cmd; (* Done *)
New.cmd; (* Done *)
Peers.cmd; (* Done *)
Pull.cmd; (* Done *)
Read.cmd; (* Done *)
Recent.cmd; (* Done *)
Topics.cmd; (* Done *)
Unfile.cmd; (* Done *)
]
let default_cmd = Term.(ret (const (`Help (`Pager, None))))
let txt =
let doc = "Discover, collect and exchange texts" in
let man = [
`S "CONTACT";
`P "<mailto:logarion-dev@chaotic.ninja>"; ]
in
Cmd.group (Cmd.info "txt" ~version:"%%VERSION%%" ~doc ~man) ~default:default_cmd subs
let main () = exit (Cmd.eval txt)
let () = main ()

View File

@ -11,23 +11,23 @@ let opt_element tag_name content =
module P = Parsers.Plain_text.Make (Converter.Html)
let id txt = "<id>urn:txtid:" ^ Logarion.(txt.Text.id) ^ "</id>\n"
let title text = "<title>" ^ esc text.Logarion.Text.title ^ "</title>\n"
let id txt = "<id>urn:txtid:" ^ Kosuzu.(txt.Text.id) ^ "</id>\n"
let title text = "<title>" ^ esc text.Kosuzu.Text.title ^ "</title>\n"
let authors text =
let u acc addr = acc ^ element "uri" addr in
let open Logarion in
let open Kosuzu in
let fn txt a =
a ^ "<author>" ^ (opt_element "name" @@ esc txt.Person.name)
^ (List.fold_left u "" txt.Person.addresses)
^ "</author>\n" in
Person.Set.fold fn text.Text.authors ""
let updated txt = let open Logarion in
let updated txt = let open Kosuzu in
"<updated>"^ Date.(txt.Text.date |> listing |> rfc_string) ^"</updated>\n"
let htm_entry base_url text =
let open Logarion in
let open Kosuzu in
let u = Text.short_id text in
"<entry>\n<link rel=\"alternate\" href=\"" ^ base_url ^ "/" ^ u ^ ".htm\" />\n"
^ title text ^ id text ^ updated text ^ authors text
@ -36,7 +36,7 @@ let htm_entry base_url text =
^ "</entry>\n"
let gmi_entry base_url text =
let open Logarion in
let open Kosuzu in
let u = Text.short_id text in
"<entry>\n<link rel=\"alternate\" href=\"" ^ base_url ^ "/" ^ u ^ ".gmi\" />\n"
^ title text ^ id text ^ updated text ^ authors text
@ -45,14 +45,14 @@ let gmi_entry base_url text =
^ "</entry>\n"
let base_url kv protocol = try
let locs = Logarion.Store.KV.find "Locations" kv in
let locs = Kosuzu.Store.KV.find "Locations" kv in
let _i = Str.(search_forward (regexp (protocol ^ "://[^;]*")) locs 0) in
Str.(matched_string locs)
with Not_found -> Printf.eprintf "Missing location for %s, add it to txt.conf\n" protocol; ""
let indices alternate_type c =
let file name = Logarion.File_store.file (Filename.concat c.Conversion.dir name) in
let title = try Logarion.Store.KV.find "Title" c.Conversion.kv with Not_found -> "" in
let file name = Kosuzu.File_store.file (Filename.concat c.Conversion.dir name) in
let title = try Kosuzu.Store.KV.find "Title" c.Conversion.kv with Not_found -> "" in
let entry, fname, protocol_regexp = match alternate_type with
| "text/gemini" -> gmi_entry, "gmi.atom", "gemini"
| "text/html" | _ -> htm_entry, "feed.atom", "https?"
@ -64,7 +64,7 @@ let indices alternate_type c =
^ title ^ {|</title><link rel="alternate" type="|} ^ alternate_type ^ {|" href="|}
^ base_url ^ {|/" /><link rel="self" type="application/atom+xml" href="|}
^ self ^ {|" /><id>urn:txtid:|} ^ c.Conversion.id ^ "</id><updated>"
^ Logarion.Date.now () ^ "</updated>\n"
^ Kosuzu.Date.now () ^ "</updated>\n"
^ List.fold_left (fun acc t -> acc ^ entry base_url t) "" c.texts
^ "</feed>"

View File

@ -1,4 +1,4 @@
open Logarion
open Kosuzu
let authors r topics_opt =
let predicates = Archive.(predicate topics topics_opt) in
let predicate text = List.fold_left (fun a e -> a && e text) true predicates in
@ -18,5 +18,5 @@ let cmd =
`S Manpage.s_description;
`P "List author names" ]
in
let info = Cmd.info "authors" ~version:"%%VERSION%%" ~doc ~man in
let info = Cmd.info "authors" ~doc ~man in
Cmd.v info authors_t

View File

@ -1,4 +1,4 @@
open Logarion
open Kosuzu
module Rel = struct
@ -60,7 +60,7 @@ type t = {
type fn_t = {
ext: string;
page: (t -> Logarion.Text.t -> string) option;
page: (t -> Kosuzu.Text.t -> string) option;
indices: (t -> unit) option;
}

View File

@ -1,6 +1,5 @@
open Logarion
open Kosuzu
(*TODO: move to converters (style, feed checks)*)
let is_older s d = try Unix.((stat d).st_mtime < (stat s).st_mtime) with _-> true
let convert cs r (text, files) = match Text.str "Content-Type" text with
@ -92,5 +91,5 @@ let cmd =
`P "If path is a directory must contain an index.pck.";
`P "Run `txt index` first." ]
in
let info = Cmd.info "convert" ~version: "%%VERSION%%" ~doc ~man in
let info = Cmd.info "convert" ~doc ~man in
Cmd.v info convert_t

6
cmd/txt/dune Normal file
View File

@ -0,0 +1,6 @@
(executable
(name txt)
(public_name txt)
(modules txt authors convert conversion edit file index last listing
new topics html atom gemini peers pull recent unfile)
(libraries text_parse.converter text_parse.parsers kosuzu msgpck curl str cmdliner))

View File

@ -7,14 +7,16 @@ let number = Arg.(value & opt (some int) None & info ["n"] ~docv: "number" ~doc:
let authed = Arg.(value & opt (some string) None & info ["authored"] ~docv: "Comma-separated names" ~doc: "Texts by authors")
let topics = Arg.(value & opt (some string) None & info ["topics"] ~docv: "Comma-separated topics" ~doc: "Texts by topics")
let edit_t = Term.(const (Logarion.Archive.apply_sys_util "EDITOR" "nano") $ recurse $ time $ reverse $ number $ authed $ topics $ id)
let edit_t = Term.(const (Kosuzu.Archive.apply_sys_util "EDITOR" "nano") $ recurse $ time $ reverse $ number $ authed $ topics $ id)
let cmd =
let doc = "Edit a text" in
let man = [
`S Manpage.s_description;
`P "Launches EDITOR (nano if environment variable is unset) with text path as parameter.";
`P "If -R is used, the ID search space includes texts found in subdirectories, too." ]
`P "If -R is used, the ID search space includes texts found in subdirectories, too.";
`S Manpage.s_environment;
`P "EDITOR - Default editor name" ]
in
let info = Cmd.info "edit" ~version:"%%VERSION%%" ~doc ~man in
let info = Cmd.info "edit" ~doc ~man in
Cmd.v info edit_t

View File

@ -1,4 +1,4 @@
open Logarion
open Kosuzu
let file files =
let dirs, files = File_store.split_filetypes files in
let _link_as_named dir file = Unix.link file (Filename.concat dir file) in
@ -19,5 +19,5 @@ let cmd =
`P "Files all texts in parameter in every directory in parameter, using hardlinks";
`P "Use it to create sub-repositories for sharing or converting" ]
in
let info = Cmd.info "file" ~version:"%%VERSION%%" ~doc ~man in
let info = Cmd.info "file" ~doc ~man in
Cmd.v info file_t

View File

@ -7,18 +7,18 @@ module GeminiConverter = struct
end
let page _conversion text =
let open Logarion.Text in
let open Kosuzu.Text in
"# " ^ text.title
^ "\nAuthors: " ^ Logarion.Person.Set.to_string text.authors
^ "\nDate: " ^ Logarion.Date.(pretty_date @@ listing text.date)
^ "\nAuthors: " ^ Kosuzu.Person.Set.to_string text.authors
^ "\nDate: " ^ Kosuzu.Date.(pretty_date @@ listing text.date)
^ let module T = Parsers.Plain_text.Make (GeminiConverter) in
"\n" ^ T.of_string text.body ""
let date_index title meta_list =
List.fold_left
(fun a m ->
a ^ "=> " ^ Logarion.Text.short_id m ^ ".gmi " ^
Logarion.(Date.(pretty_date (listing m.date)) ^ " " ^ m.title) ^ "\n")
a ^ "=> " ^ Kosuzu.Text.short_id m ^ ".gmi " ^
Kosuzu.(Date.(pretty_date (listing m.date)) ^ " " ^ m.title) ^ "\n")
("# " ^ title ^ "\n\n## Posts by date\n\n") meta_list
let to_dated_links ?(limit) meta_list =
@ -33,9 +33,9 @@ let to_dated_links ?(limit) meta_list =
List.fold_left
(fun a m ->
a
^ "=> " ^ Logarion.Text.short_id m ^ ".gmi "
^ Logarion.(Date.(pretty_date (listing m.Text.date))) ^ " "
^ m.Logarion.Text.title ^ "\n")
^ "=> " ^ Kosuzu.Text.short_id m ^ ".gmi "
^ Kosuzu.(Date.(pretty_date (listing m.Text.date))) ^ " "
^ m.Kosuzu.Text.title ^ "\n")
"" meta_list
let topic_link root topic =
@ -43,7 +43,7 @@ let topic_link root topic =
"=> index." ^ replaced_space root ^ ".gmi " ^ String.capitalize_ascii topic ^ "\n"
let text_item path meta =
let open Logarion in
let open Kosuzu in
"=> " ^ path ^ Text.short_id meta ^ ".gmi "
^ Date.(pretty_date (listing meta.Text.date)) ^ " "
^ meta.Text.title ^ "\n"
@ -51,15 +51,15 @@ let text_item path meta =
let listing_index topic_map topic_roots path metas =
let rec item_group topics =
List.fold_left (fun acc topic -> acc ^ sub_groups topic ^ items topic) "" topics
and sub_groups topic = match Logarion.Topic_set.Map.find_opt topic topic_map with
and sub_groups topic = match Kosuzu.Topic_set.Map.find_opt topic topic_map with
| None -> ""
| Some (_, subtopics) -> item_group (Logarion.String_set.elements subtopics)
| Some (_, subtopics) -> item_group (Kosuzu.String_set.elements subtopics)
and items topic =
let items =
let open Logarion in
let open Kosuzu in
List.fold_left
(fun a e ->
if String_set.mem topic (String_set.map (Logarion.Topic_set.topic) (Text.set "Topics" e))
if String_set.mem topic (String_set.map (Kosuzu.Topic_set.topic) (Text.set "Topics" e))
then text_item path e ^ a else a) "" metas in
match items with
| "" -> ""
@ -76,7 +76,7 @@ let topic_main_index r title topic_roots metas =
^ (if topic_roots <> [] then ("## Main topics\n\n" ^ fold_topic_roots topic_roots) else "")
^ "\n## Latest\n\n" ^ to_dated_links ~limit:10 metas
^ "\n=> index.date.gmi More by date\n\n"
^ let peers = Logarion.Store.KV.find "Peers" r.Conversion.kv in
^ let peers = Kosuzu.Store.KV.find "Peers" r.Conversion.kv in
if peers = "" then "" else
List.fold_left (fun a s -> Printf.sprintf "%s=> %s\n" a s) "## Peers\n\n"
(Str.split (Str.regexp ";\n") peers)
@ -86,7 +86,7 @@ let topic_sub_index title topic_map topic_root metas =
^ listing_index topic_map [topic_root] "" metas
let indices r =
let open Logarion in
let open Kosuzu in
let file name = File_store.file (Filename.concat r.Conversion.dir name) in
let index_name = try Store.KV.find "Gemini-index" r.kv with Not_found -> "index.gmi" in
let title = try Store.KV.find "Title" r.Conversion.kv with Not_found -> "" in

View File

@ -6,7 +6,7 @@ let empty_templates = { header = None; footer = None }
let default_opts = { templates = empty_templates; style = "" }
let init kv =
let open Logarion in
let open Kosuzu in
let to_string key kv = match Store.KV.find key kv with
| fname -> Some (File_store.to_string fname)
| exception Not_found -> None in
@ -17,12 +17,12 @@ let init kv =
{ templates = { header; footer}; style }
let wrap conv htm text_title body =
let site_title = try Logarion.Store.KV.find "Title" conv.Conversion.kv with Not_found -> "" in
let site_title = try Kosuzu.Store.KV.find "Title" conv.Conversion.kv with Not_found -> "" in
let replace x = let open Str in
global_replace (regexp "{{archive-title}}") site_title x
|> global_replace (regexp "{{text-title}}") text_title
in
let feed = try Logarion.Store.KV.find "HTM-feed" conv.Conversion.kv
let feed = try Kosuzu.Store.KV.find "HTM-feed" conv.Conversion.kv
with Not_found -> if Sys.file_exists (Filename.concat conv.Conversion.dir "feed.atom")
then "feed.atom" else "" in
let header = match htm.templates.header with
@ -31,7 +31,7 @@ let wrap conv htm text_title body =
(if feed <> "" then sprintf "<a href='%s' id='feed'>feed</a>" feed else ""))
in
let footer = match htm.templates.footer with None -> "" | Some x -> replace x in
Printf.sprintf "<!DOCTYPE HTML>\n<html>\n<head>\n<link rel=\"icon\" href=\"/favicon.ico\">\n<title>%s%s</title>\n%s\n%s\n<meta name=\"generator\" content=\"Logarion\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n</head>\n<body>\n%s%s%s</body>\n</html>"
Printf.sprintf "<!DOCTYPE HTML>\n<html>\n<head>\n<link rel=\"icon\" href=\"/favicon.ico\">\n<title>%s%s</title>\n%s\n%s\n<meta name=\"generator\" content=\"Kosuzu\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n</head>\n<body>\n%s%s%s</body>\n</html>"
text_title (if site_title <> "" then (" &bull; " ^ site_title) else "")
htm.style
(if feed <> "" then Printf.sprintf "<link rel='alternate' href='%s' type='application/atom+xml'>" feed else "")
@ -51,7 +51,7 @@ module HtmlConverter = struct
end
let page htm conversion text =
let open Logarion in
let open Kosuzu in
let open Text in
let module T = Parsers.Plain_text.Make (HtmlConverter) in
let sep_append ?(sep=", ") a x = match a,x with "",_ -> x | _, "" -> a | _ -> a ^ sep ^ x in
@ -95,8 +95,8 @@ let to_dated_links ?(limit) meta_list =
| h::t -> if i < limit then reduced (h::acc) (i+1) t else acc in
List.rev @@ reduced [] 0 meta_list in
List.fold_left
(fun a m -> Printf.sprintf "%s <li> %s <a href=\"%s.htm\">%s</a>" a Logarion.(Date.(pretty_date (listing m.Text.date)))
(Logarion.Text.short_id m) m.Logarion.Text.title)
(fun a m -> Printf.sprintf "%s <li> %s <a href=\"%s.htm\">%s</a>" a Kosuzu.(Date.(pretty_date (listing m.Text.date)))
(Kosuzu.Text.short_id m) m.Kosuzu.Text.title)
"" meta_list
let date_index ?(limit) conv htm meta_list =
@ -111,7 +111,7 @@ let fold_topic_roots topic_roots =
^ "</ul></nav>"
let fold_topics topic_map topic_roots metas =
let open Logarion in
let open Kosuzu in
let rec unordered_list root topic =
List.fold_left (fun a x -> a ^ list_item root x) "<ul>" topic
^ "</ul>"
@ -128,7 +128,7 @@ and list_item root t =
^ "</ul></nav>"
let text_item path meta =
let open Logarion in
let open Kosuzu in
"<time>" ^ Date.(pretty_date (listing meta.Text.date))
^ {|</time> <a href="|} ^ path ^ Text.short_id meta ^ {|.htm">|} ^ meta.Text.title
^ "</a><br>"
@ -136,15 +136,15 @@ let text_item path meta =
let listing_index topic_map topic_roots path metas =
let rec item_group topics =
List.fold_left (fun acc topic -> acc ^ sub_groups topic ^ items topic) "" topics
and sub_groups topic = match Logarion.Topic_set.Map.find_opt topic topic_map with
and sub_groups topic = match Kosuzu.Topic_set.Map.find_opt topic topic_map with
| None -> ""
| Some (_, subtopics) -> item_group (Logarion.String_set.elements subtopics)
| Some (_, subtopics) -> item_group (Kosuzu.String_set.elements subtopics)
and items topic =
let items =
let open Logarion in
let open Kosuzu in
List.fold_left
(fun a e ->
if String_set.mem topic (String_set.map (Logarion.Topic_set.topic) (Text.set "Topics" e))
if String_set.mem topic (String_set.map (Kosuzu.Topic_set.topic) (Text.set "Topics" e))
then text_item path e ^ a else a) "" metas in
match items with
| "" -> ""
@ -156,10 +156,10 @@ let topic_main_index conv htm topic_roots metas =
(fold_topic_roots topic_roots
^ "<nav><h1>Latest</h1><ul>" ^ to_dated_links ~limit:10 metas
^ {|</ul></nav><hr><a href="index.date.htm">More by date</a>|}
^ let peers = try Logarion.Store.KV.find "Peers" conv.kv with Not_found -> "" in
^ let peers = try Kosuzu.Store.KV.find "Peers" conv.kv with Not_found -> "" in
(if peers = "" then "" else
List.fold_left (fun a s -> Printf.sprintf {|%s<li><a href="%s">%s</a>|} a s s) "<h1>Peers</h1><ul>"
(Str.split (Str.regexp ";\n") (Logarion.Store.KV.find "Peers" conv.kv))
(Str.split (Str.regexp ";\n") (Kosuzu.Store.KV.find "Peers" conv.kv))
^ "</ul>"))
let topic_sub_index conv htm topic_map topic_root metas =
@ -168,8 +168,8 @@ let topic_sub_index conv htm topic_map topic_root metas =
^ listing_index topic_map [topic_root] "" metas)
let indices htm c =
let file name = Logarion.File_store.file (Filename.concat c.Conversion.dir name) in
let index_name = try Logarion.Store.KV.find "HTM-index" c.Conversion.kv with Not_found -> "index.html" in
let file name = Kosuzu.File_store.file (Filename.concat c.Conversion.dir name) in
let index_name = try Kosuzu.Store.KV.find "HTM-index" c.Conversion.kv with Not_found -> "index.html" in
if index_name <> "" then file index_name (topic_main_index c htm c.topic_roots c.texts);
file "index.date.htm" (date_index c htm c.texts);
List.iter

View File

@ -1,4 +1,4 @@
open Logarion
open Kosuzu
let text_editor name x =
let fname, out = Filename.open_temp_file name "" in
@ -85,7 +85,9 @@ let cmd =
`P "* n info section with: title for the index, the authors, locations (URLs) the texts can be accessed.";
`P "* listing of texts with: ID, date, title, authors, topics.";
`P "* list of other text repositories (peers)";
`S Manpage.s_environment;
`P "EDITOR - Default editor name";
`S Manpage.s_see_also;
`P "MessagePack format. https://msgpack.org" ] in
let info = Cmd.info "index" ~version:"%%VERSION%%" ~doc ~man in
let info = Cmd.info "index" ~doc ~man in
Cmd.v info index_t

View File

@ -1,4 +1,4 @@
open Logarion
open Kosuzu
let last a ((t,_) as pair) = match a with
| None -> Some pair
@ -31,5 +31,5 @@ let cmd =
`S Manpage.s_description;
`P "Print the filename of most recent text" ]
in
let info = Cmd.info "last" ~version:"%%VERSION%%" ~doc ~man in
let info = Cmd.info "last" ~doc ~man in
Cmd.v info last_t

View File

@ -1,4 +1,4 @@
open Logarion
open Kosuzu
module FS = File_store
module A = Archive
@ -40,5 +40,5 @@ let cmd =
`P "If directory argument is omitted, TXTDIR is used, where empty value defaults to ~/.local/share/texts.";
`P "If -R is used, list header information for texts found in subdirectories, too." ]
in
let info = Cmd.info "list" ~version:"%%VERSION%%" ~doc ~man in
let info = Cmd.info "list" ~doc ~man in
Cmd.v info listing_t

View File

@ -1,29 +1,29 @@
open Logarion
open Kosuzu
open Cmdliner
let new_txt title topics_opt interactive =
let kv = Logarion.File_store.of_kv_file () in
let authors = Person.Set.of_string (try Logarion.Store.KV.find "Authors" kv
let new_txt title topics_opt =
let kv = Kosuzu.File_store.of_kv_file () in
let authors = Person.Set.of_string (try Kosuzu.Store.KV.find "Authors" kv
with Not_found -> Sys.getenv "USER") in
let text = { (Text.blank ()) with title; authors } in
let text = try Text.with_str_set text "Topics" (Option.get topics_opt) with _->text in
match File_store.with_text text with
| Error s -> prerr_endline s
| Ok (filepath, _note) ->
if interactive then (Sys.command ("$EDITOR " ^ filepath) |> ignore);
print_endline filepath
let title = Arg.(value & pos 0 string "" & info [] ~docv: "title" ~doc: "Title for new article")
let topics = Arg.(value & opt (some string) None & info ["t"; "topics"] ~docv: "Comma-separated topics" ~doc: "Topics for new article")
let inter = Arg.(value & flag & info ["i"; "interactive"] ~doc: "Prompt through the steps of creation")
let new_t = Term.(const new_txt $ title $ topics $ inter)
let new_t = Term.(const new_txt $ title $ topics)
let cmd =
let doc = "Create a new article" in
let man = [
`S Manpage.s_description;
`P "Create a new article, with title 'Draft' when none provided" ]
`P "Create a new article";
`S Manpage.s_environment;
`P "USER - The login name of the user, used if the Authors field is blank" ]
in
let info = Cmd.info "new" ~version:"%%VERSION%%" ~doc ~man in
let info = Cmd.info "new" ~doc ~man in
Cmd.v info new_t

View File

@ -1,20 +1,20 @@
let print_peers_of_peer p =
let open Logarion.Header_pack in
let open Kosuzu.Header_pack in
match Msgpck.to_list p.peers with [] -> ()
| ps -> print_endline @@
List.fold_left (fun a x -> Printf.sprintf "%s %s" a (Msgpck.to_string x)) "peers: " ps
type filter_t = { authors: Logarion.Person.Set.t; topics: Logarion.String_set.t }
type filter_t = { authors: Kosuzu.Person.Set.t; topics: Kosuzu.String_set.t }
let print_peer () peer =
let open Logarion.Peers in
let open Kosuzu.Peers in
Printf.printf "%s" peer.path;
List.iter (Printf.printf "\t%s\n") peer.pack.info.locations
let remove_repo id =
let repopath = Filename.concat Logarion.Peers.text_dir id in
let repopath = Filename.concat Kosuzu.Peers.text_dir id in
match Sys.is_directory repopath with
| false -> Printf.eprintf "No repository %s in %s" id Logarion.Peers.text_dir
| false -> Printf.eprintf "No repository %s in %s" id Kosuzu.Peers.text_dir
| true ->
let cmd = Printf.sprintf "rm -r %s" repopath in
Printf.printf "Run: %s ? (y/N) %!" cmd;
@ -25,8 +25,8 @@ let remove_repo id =
let peers = function
| Some id -> remove_repo id
| None ->
Printf.printf "Peers in %s\n" Logarion.Peers.text_dir;
Logarion.Peers.fold print_peer ()
Printf.printf "Peers in %s\n" Kosuzu.Peers.text_dir;
Kosuzu.Peers.fold print_peer ()
open Cmdliner
let remove = Arg.(value & opt (some string) None & info ["remove"] ~docv:"Repository ID" ~doc:"Remove repository texts and from future pulling")
@ -38,5 +38,5 @@ let cmd =
`S Manpage.s_description;
`P "List current peers and associated information" ]
in
let info = Cmd.info "peers" ~version:"%%VERSION%%" ~doc ~man in
let info = Cmd.info "peers" ~doc ~man in
Cmd.v info peers_t

View File

@ -2,15 +2,6 @@ let writer accum data =
Buffer.add_string accum data;
String.length data
let showContent content =
Printf.printf "%s" (Buffer.contents content);
flush stdout
let showInfo connection =
Printf.printf "Time: %f for: %s\n"
(Curl.get_totaltime connection)
(Curl.get_effectiveurl connection)
let getContent connection url =
Curl.set_url connection url;
Curl.perform connection
@ -25,8 +16,6 @@ let curl_pull url =
Curl.set_followlocation connection true;
Curl.set_url connection url;
Curl.perform connection;
(* showContent result;*)
(* showInfo connection;*)
Curl.cleanup connection;
Ok result
with
@ -38,18 +27,18 @@ let curl_pull url =
Error (Printf.sprintf "Caught exception: %s" s)
let newer time id dir =
match Logarion.File_store.to_text @@ Filename.(concat dir (Logarion.Id.short id) ^ ".txt") with
match Kosuzu.File_store.to_text @@ Filename.(concat dir (Kosuzu.Id.short id) ^ ".txt") with
| Error x -> prerr_endline x; true
| Ok txt -> time > (Logarion.(Header_pack.date (Date.listing txt.date)))
| Ok txt -> time > (Kosuzu.(Header_pack.date (Date.listing txt.date)))
| exception (Sys_error _) -> true
let print_peers p =
let open Logarion.Header_pack in
let open Kosuzu.Header_pack in
match Msgpck.to_list p.peers with [] -> ()
| ps -> print_endline @@
List.fold_left (fun a x -> Printf.sprintf "%s %s" a (Msgpck.to_string x)) "peers: " ps
type filter_t = { authors: Logarion.Person.Set.t; topics: Logarion.String_set.t }
type filter_t = { authors: Kosuzu.Person.Set.t; topics: Kosuzu.String_set.t }
let print_pull_start width total title dir =
Printf.printf "%*d/%s %s => %s %!" width 0 total title dir
@ -62,14 +51,14 @@ let printers total title dir =
print_pull_start width total title dir;
print_pull width total
let fname dir text = Filename.concat dir (Logarion.Text.short_id text ^ ".txt")
let fname dir text = Filename.concat dir (Kosuzu.Text.short_id text ^ ".txt")
let pull_text url dir id =
let u = Filename.concat url ((Logarion.Id.short id) ^ ".txt") in
let u = Filename.concat url ((Kosuzu.Id.short id) ^ ".txt") in
match curl_pull u with
| Error msg -> Printf.eprintf "Failed getting %s: %s" u msg
| Ok txt -> let txt = Buffer.contents txt in
match Logarion.Text.of_string txt with
match Kosuzu.Text.of_string txt with
| Error s -> prerr_endline s
| Ok text ->
let file = open_out_gen [Open_creat; Open_trunc; Open_wronly] 0o640 (fname dir text) in
@ -77,7 +66,7 @@ let pull_text url dir id =
let per_text url dir filter print i id time title authors topics _refs _reps = match id with
| "" -> Printf.eprintf "\nInvalid id for %s\n" title
| id -> let open Logarion in
| id -> let open Kosuzu in
print i;
if newer time id dir
&& (String_set.empty = filter.topics
@ -86,48 +75,41 @@ let per_text url dir filter print i id time title authors topics _refs _reps = m
|| Person.Set.exists (fun t -> List.mem (Person.to_string t) authors) filter.authors)
then pull_text url dir id
(*TODO: integrate in lib*)
let validate_id_length s = String.length s <= 32
let validate_id_chars s = try
String.iter (function 'a'..'z'|'A'..'Z'|'0'..'9'-> () | _ -> raise (Invalid_argument "")) s;
true
with Invalid_argument _ -> false
let pull_index url authors_opt topics_opt =
let index_url = Filename.concat url "index.pck" in
match curl_pull index_url with
| Error s -> prerr_endline s; false
| Ok body ->
match Logarion.Header_pack.of_string (Buffer.contents body) with
match Kosuzu.Header_pack.of_string (Buffer.contents body) with
| Error s -> Printf.printf "Error with %s: %s\n" url s; false
| Ok pk when pk.info.id = "" ->
Printf.printf "Empty ID index.pck, skipping %s\n" url; false
| Ok pk when not (validate_id_length pk.info.id) ->
| Ok pk when not (Kosuzu.Validate.validate_id_length pk.info.id) ->
Printf.printf "Index pack ID longer than 32 characters, skipping %s\n" url; false
| Ok pk when not (validate_id_chars pk.info.id) ->
| Ok pk when not (Kosuzu.Validate.validate_id_chars pk.info.id) ->
Printf.printf "Index pack contains invalid ID characters, skipping %s\n" url; false
| Ok pk ->
let dir = Filename.concat Logarion.Peers.text_dir pk.info.id in
Logarion.File_store.with_dir dir;
let dir = Filename.concat Kosuzu.Peers.text_dir pk.info.id in
Kosuzu.File_store.with_dir dir;
let file = open_out_gen [Open_creat; Open_trunc; Open_wronly] 0o640
(Filename.concat dir "index.pck") in
output_string file ( Logarion.Header_pack.string {
output_string file ( Kosuzu.Header_pack.string {
pk with info = { pk.info with locations = url::pk.info.locations }});
close_out file;
let filter = let open Logarion in {
let filter = let open Kosuzu in {
authors = (match authors_opt with Some s -> Person.Set.of_string s | None -> Person.Set.empty);
topics =( match topics_opt with Some s -> String_set.of_string s | None -> String_set.empty);
} in
let name = match pk.info.title with "" -> url | title -> title in
let print = printers (string_of_int @@ Logarion.Header_pack.numof_texts pk) name dir in
try Logarion.Header_pack.iteri (per_text url dir filter print) pk; print_newline (); true
let print = printers (string_of_int @@ Kosuzu.Header_pack.numof_texts pk) name dir in
try Kosuzu.Header_pack.iteri (per_text url dir filter print) pk; print_newline (); true
with Invalid_argument msg -> Printf.printf "\nFailed to parse %s: %s\n%!" url msg; false
let pull_list auths topics =
Curl.global_init Curl.CURLINIT_GLOBALALL;
let pull got_one peer_url = if got_one then got_one else
(pull_index peer_url auths topics) in
let open Logarion in
let open Kosuzu in
let fold_locations init peer =
ignore @@ List.fold_left pull init peer.Peers.pack.Header_pack.info.locations;
false
@ -151,5 +133,5 @@ let cmd =
`S Manpage.s_description;
`P "Pull texts from known repositories." ]
in
let info = Cmd.info "pull" ~version:"%%VERSION%%" ~doc ~man in
let info = Cmd.info "pull" ~doc ~man in
Cmd.v info pull_t

View File

@ -1,4 +1,4 @@
open Logarion
open Kosuzu
module FS = File_store
module A = Archive
@ -19,5 +19,5 @@ let cmd =
`P "List header information of most recent texts.";
`P "If -R is used, list header information for texts found in subdirectories, too, along with their filepaths" ]
in
let info = Cmd.info "recent" ~version:"%%VERSION%%" ~doc ~man in
let info = Cmd.info "recent" ~doc ~man in
Cmd.v info recent_t

View File

@ -1,4 +1,4 @@
open Logarion
open Kosuzu
let topics r authors_opt =
let predicates = Archive.(predicate authored authors_opt) in
let predicate text = List.fold_left (fun a e -> a && e text) true predicates in
@ -17,5 +17,5 @@ let cmd =
`S Manpage.s_description;
`P "List of topics" ]
in
let info = Cmd.info "topics" ~version:"%%VERSION%%" ~doc ~man in
let info = Cmd.info "topics" ~doc ~man in
Cmd.v info topics_t

36
cmd/txt/txt.ml Normal file
View File

@ -0,0 +1,36 @@
open Cmdliner
let subs = [
Authors.cmd;
Convert.cmd;
Edit.cmd;
File.cmd;
Index.cmd;
Last.cmd;
Listing.cmd;
New.cmd;
Peers.cmd;
Pull.cmd;
Recent.cmd;
Topics.cmd;
Unfile.cmd;
]
let default_cmd = Term.(ret (const (`Help (`Pager, None))))
let txt =
let doc = "Discover, collect and exchange texts" in
let man = [
`S Manpage.s_authors;
`P "orbifx <mailto:fox@orbitalfox.eu>";
`P "Izuru Yakumo <mailto:yakumo.izuru@chaotic.ninja>";
`S Manpage.s_bugs;
`P "Please report them at <mailto:kosuzu-dev@chaotic.ninja>";
`S Manpage.s_see_also;
`P "This program is named after Kosuzu Motoori from Touhou Suzunaan: Forbidden Scrollery";
`P "https://en.touhouwiki.net/wiki/Forbidden_Scrollery" ]
in
Cmd.group (Cmd.info "txt" ~version:"%%VERSION%%" ~doc ~man) ~default:default_cmd subs
let main () = exit (Cmd.eval txt)
let () = main ()

View File

@ -1,4 +1,4 @@
open Logarion
open Kosuzu
let unfile files =
let dirs, files = File_store.split_filetypes files in
@ -17,5 +17,5 @@ let cmd =
`S Manpage.s_description;
`P "Unfile texts in parameter from directories in parameter, by removing hardlinks" ]
in
let info = Cmd.info "unfile" ~version:"%%VERSION%%" ~doc ~man in
let info = Cmd.info "unfile" ~doc ~man in
Cmd.v info unfile_t

5
cmd/txt_init/dune Normal file
View File

@ -0,0 +1,5 @@
(executable
(name txt_init)
(public_name txt_init)
(modules txt_init)
(libraries kosuzu))

17
cmd/txt_init/txt_init.ml Normal file
View File

@ -0,0 +1,17 @@
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

View File

@ -1,11 +0,0 @@
ID: 3sqd84
Date: 2022-11-06T13:01:19Z
Title: Exploring & pulling texts from Logarion repositories
Authors: orbifx
Topics: Logarion
Logarion repositories are collections of text files, accompanied by a special index file. These collections can exist on any server and accessed by any transport protocol. Logarion's client currently supports a plethora of protocols, HTTP, FTP, Gopher to name a few examples.
A remote repository can be registered and texts copied locally. To add a new remote run: `txt pull <url>`, where <url> is the address of the remote repository. The program will connect to the server, copy the `index.pck` file and use it to download each text file. It will not redownload previous texts, unless their Date or Date-Edited dates are newer than the previous ones.
The text files are by default downloaded to `.local/share/texts/peers/`. A new directory is created for each peer's unique id and the index & texts are stored in it. Running `txt pull` with no URL, will refetch indices from all previously pulled repositories, and new text files will be downloaded automatically.

View File

@ -1,15 +0,0 @@
ID: 9egbae
Date: 2023-06-17T23:27:44Z
Title: Building from source
Authors: Izuru Yakumo
Topics: Logarion
Requirements:
* git
* ocaml (>=4.13)
1. git clone git://git.chaotic.ninja/yakumo_izuru/logarion
2. cd logarion
3. git submodule update --init
4. make deps
5. make tgz

View File

@ -1,23 +0,0 @@
all: clean build
build: index generate
clean:
find htm -type f -name "*.html" -print -delete
find htm -type f -name "*.htm" -print -delete
find . -type f -name "*.atom" -print -delete
copy-index: index
cp index.pck htm
generate: relink copy-index
txt convert --type=htm htm
index:
txt index .
link:
txt file *.txt htm
delink:
rm htm/*.txt
serve:
darkhttpd htm
upload:
rsync -acv --del htm/ webdev@chaotic.ninja:/var/www/logarion
relink: delink link

View File

@ -1,26 +0,0 @@
ID: d41e68
Date: 2023-10-18T18:45:33+00:00
Title: Header format
Authors: orbifx <fox@orbitalfox.eu>
Topics: Logarion
ID: Unique identifier
Date: ISO8601 date of creation
Topics: Comma seperated list of topic names & phrases
Title: A title for the text, ideally less than 70 characters
Authors: List of name with optional set of <address>
Date-edited: ISO8601, use only when text edited
References: list of text ID links
A blank line must follow the last header field.
Example
ID: 11bcd
Title: A Logarion exemplar header
Authors: John Doe <http://example.com> <jd@example.com>
Date: 1970-11-06T12:29:50-00:00
Topic: Logarion, examples
Hello world!

View File

@ -1,4 +0,0 @@
<hr>
<p>
<a href="git://git.chaotic.ninja/yakumo_izuru/logarion">Source code</a>
</p>

View File

@ -1,17 +0,0 @@
ID: h1a9tg
Date: 2022-11-20T13:28:57Z
Authors: orbifx <orbifx@orbifx.indy>
Title: Txt uniform resource names
Topics: Logarion
Logarion texts are transport agnostic. URIs should therefore avoid using URLs and use URNs instead. Some definitions of Uniform Resource:
- Locator (URL) <http://en.wikipedia.org/wiki/Url>
- Identifier (URI) <http://en.wikipedia.org/wiki/Uniform_Resource_Identifier>
- Name (URN) <http://en.wikipedia.org/wiki/Uniform_Resource_Name>
Links enclosed in angled brackets <> of the format:
urn:txtid:abcdef
where `abcdef` is the id of the text are understood by `txt` and handled accordingly. For example when converting to HTML or Gemini, the URNs are converted to relative URLs which browsers can understand.

View File

@ -1,2 +0,0 @@
<h1>Logarion</h1>
<p>discover, collect &amp; exchange plain text files</p>

Binary file not shown.

View File

@ -1,8 +0,0 @@
body{color:#111;background:#faeed6;margin:auto;padding:1ch;max-width:80ch}
@media(min-resolution:130dpi){body{font-size:1.5em}}
article>header{margin:auto;padding:1ch}
dt{float:left;text-align:right;padding-right:1ch;min-width:8ch;opacity:0.4;clear:left}
:target::before{content:"☞"}
body>h1{font-family:cursive}
h1,h2{color:#ff6600}
h3,h4{color:#333}

View File

@ -1,77 +0,0 @@
ID: hvhhwf
Date: 2022-11-06T13:19:57Z
Title: Creating texts & publishing on the net
Authors: orbifx
Topics: Logarion
# New
To create new text files, use "txt new". For example:
txt new "Hello world"
It's important to enclose the title with quotation marks if it contains spaces. The command will return the filename of the new text. The filename starts with a part of the ID and the title of the text. Use the file name to open it with your text editor.
Alternatively add the -i flag to have the text editor launched to edit the newly created file:
txt new -i "Some title"
Text files will be stored in either:
1. The directory pointed at by txtdir if defined
2. $HOME/.local/share/texts, if directory exists
3. The current working directory, if all else fails
The simplest approach is to put all texts in the local-share directory and override that on occasion with
$txtdir. For example:
txtdir=. txt new "Hello world"
# Publish
Texts created with "new" are treated as personal until published. To publish a text, use `txt publish [id]` where [id] is the text of the text to publish. Publication requires a `txt.conf` file which must exist in either:
1. The current working directory
2. $HOME/.config/txt/txt.conf
With the above in place, `txt publish [id]` will add the text file with [id] in the publication-directory and reproduce the `index.pck` in that directory. If Pubdir is not defined in `txt.conf` then the environmental variable `txtpubdir` is used. If that is also undefined, the current working directory is used as a publication directory.
Logarion is protocol agnostic, so publish looks for the existence of directories to copy the files, ready for publication. At the time of writing the three directories are `public_html`, `public_gemini` and `public_gopher`. For each of these directories, `txt publish [id]` will copy the text file, revise the `index.pck` and also convert produce converted files, such .htm for public_html.
## txt.conf keys
Id:
A random, unique, alphanumeric string for distinguishing the repository (atleast 6 characters of Crockford's Base32 recommended)
Title:
a human-friendly title
Authors:
comma seperated list of names and, optionally, addresses
Topics:
topics the repository aims to cover
Locations:
list of URIs the repositories can be accessed
Peers:
list of peer URIs
Pubdir:
(optional) the directory that contains publication subdirectories
## HTML
There are some special settings for HTML publication:
HTM-style:
path to a CSS style. It will be inserted in every .htm file. To link to a single CSS consider using `@import`
HTM-header:
path to a file, inserted in every .htm file, right after the body tag
HTM-footer:
path to a file, inserted in every .htm file, right before the body tag
HTM-index:
if defined, determines the filename for the index files. Left undefined, defaults to `index.html`
HTM-feed:
if defined, this will overrite the feed URI used in HTML files. If left undefined the default `feed.atom` is used

Binary file not shown.

View File

@ -1,8 +0,0 @@
body{color:#111;background:#faeed6;margin:auto;padding:1ch;max-width:80ch}
@media(min-resolution:130dpi){body{font-size:1.5em}}
article>header{margin:auto;padding:1ch}
dt{float:left;text-align:right;padding-right:1ch;min-width:8ch;opacity:0.4;clear:left}
:target::before{content:"☞"}
body>h1{font-family:cursive}
h1,h2{color:#ff6600}
h3,h4{color:#333}

View File

@ -1,8 +0,0 @@
Id: 17f4e3
Title: Logarion
Authors: orbifx <fox@orbifalfox.eu>, Izuru Yakumo <yakumo.izuru@chaotic.ninja>
HTM-style: main.css
HTM-header: header.html
HTM-footer: footer.html
HTM-feed:
Topics: Logarion

View File

@ -1,16 +1,16 @@
(lang dune 2.0)
(name logarion)
(version 1.4.0)
(name kosuzu)
(version 1.4.3)
(license EUPL-1.2)
(authors "orbifx <fox@orbitalfox.eu>")
(bug_reports "mailto:logarion-dev@chaotic.ninja")
(bug_reports "mailto:kosuzu-dev@chaotic.ninja")
(maintainers "Izuru Yakumo <yakumo.izuru@chaotic.ninja>")
(homepage "https://suzunaan.chaotic.ninja/logarion/")
(source (uri https://git.chaotic.ninja/yakumo.izuru/logarion))
(homepage "https://suzunaan.chaotic.ninja/kosuzu/")
(source (uri git+https://git.chaotic.ninja/yakumo.izuru/kosuzu))
(generate_opam_files true)
(package
(name logarion)
(name kosuzu)
(synopsis "Texts archival and exchange")
(depends ocaml dune ocurl msgpck cmdliner))

View File

@ -1,12 +1,12 @@
# This file is generated by dune, edit dune-project instead
opam-version: "2.0"
version: "1.4.0"
version: "1.4.3"
synopsis: "Texts archival and exchange"
maintainer: ["Izuru Yakumo <yakumo.izuru@chaotic.ninja>"]
authors: ["orbifx <fox@orbitalfox.eu>"]
license: "EUPL-1.2"
homepage: "https://suzunaan.chaotic.ninja/logarion/"
bug-reports: "mailto:logarion-dev@chaotic.ninja"
homepage: "https://suzunaan.chaotic.ninja/kosuzu/"
bug-reports: "mailto:kosuzu-dev@chaotic.ninja"
depends: ["ocaml" "dune" "ocurl" "msgpck" "cmdliner"]
build: [
["dune" "subst"] {pinned}
@ -22,4 +22,4 @@ build: [
"@doc" {with-doc}
]
]
dev-repo: "https://git.chaotic.ninja/yakumo.izuru/logarion"
dev-repo: "git+https://git.chaotic.ninja/yakumo.izuru/kosuzu"

View File

@ -1,4 +1,4 @@
(library
(name logarion)
(public_name logarion)
(name kosuzu)
(public_name kosuzu)
(libraries text_parse text_parse.parsers unix str msgpck))

5
lib/validate.ml Normal file
View File

@ -0,0 +1,5 @@
let validate_id_length s = String.length s <= 32
let validate_id_chars s = try
String.iter (function 'a'..'z'|'A'..'Z'|'0'..'9'-> () | _ -> raise (Invalid_argument "")) s;
true
with Invalid_argument _ -> false