;;; TDM.el --- editing Taler docs.git/manpages/* -*- lexical-binding: t -*- ;; Copyright (C) 2021, 2022 Taler Systems SA ;; ;; This file is part of GNU TALER. ;; ;; TALER is free software; you can redistribute it and/or modify it ;; under the terms of the GNU Affero General Public License as ;; published by the Free Software Foundation; either version 2.1, ;; or (at your option) any later version. ;; ;; TALER is distributed in the hope that it will be useful, but ;; WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU Affero General Public License for more details. ;; ;; You should have received a copy of the GNU Affero General Public ;; License along with TALER; see the file COPYING. If not, see ;; . ;; ;; Author: Thien-Thi Nguyen ;;; Commentary: ;; This library currently provides two commands: ‘TDM-convert-options’ ;; and ‘TDM-recursive-help’. ;; ;; * ‘TDM-convert-options’ ;; The intended workflow is simple: ;; - Create a new file from template. ;; - Do the substitutions / deletions as necessary. ;; - Split the window, one half for Synopsis, one for Description. ;; - Do ‘COMMAND --help’ and copy the portion of its output that ;; describes the options into the buffer in the Synopsis section. ;; + Place point at bol of an option and call ‘TDM-convert-options’. ;; (Personally, I locally bind this to ‘C-c C-o’.) ;; - Set mark at point and move point to the end of the ;; description text (for that option). ;; - Kill the region (with ‘C-w’). ;; - Switch to the other window, find a suitable place, and ;; yank (with ‘C-y’) the text there. ;; - Edit the description as necessary. ;; - Loop from "+" until finished. ;; ;; At the end, you may have to delete some extra blank lines ;; in the Synopsis section. ;; ;; ‘TDM-convert-options’ takes a prefix arg, which inhibits the ;; deletion of the original (--help output) text. This can be ;; useful if you don't trust (yet :-D) the conversion process. ;; ;; There are a couple TODO items, which point to situations that ;; have not yet arisen in practice, but that might theoretically ;; bother us in the future. ;; ;; * ‘TDM-recursive-help’ ;; This command is intended for libeufin programs, specifically ;; libeufin-sandbox, libeufin-nexus, and libeufin-cli. However, ;; it should work with any Java program that uses clikt, or any ;; Python program that uses click, for its command-line handling. ;; ;; You can obtain the --help output (recursively) in a buffer ;; and write it to a file for further analysis / processing. ;;; Code: (require 'cl-lib) (defun TDM-parse-option-triple () "Return a triple formed by parsing option text at point. The triple has the form (ARG SHORT LONG), where each element can be either a string or ‘nil’. Signal error if parsing fails. Leave point after the end of the parsed text." (cl-flet ((peer (regexp) (re-search-forward regexp (line-end-position) t))) (cond ;; Full form: (ARG SHORT LONG). ((peer " *-\\(.\\), --\\([^=\n]+\\)=\\(\\S +\\)") (mapcar #'match-string-no-properties (list 3 1 2))) ;; No argument: (nil SHORT LONG). ((peer " *-\\(.\\), --\\(\\S +\\)") (list nil (match-string-no-properties 1) (match-string-no-properties 2))) ;; TODO: Handle other combinations. (t (error "Could not parse option text"))))) (defun TDM-insert-options (arg short long) "Insert formatted options, twice (on two lines). The first is for the Synopsis section, the second for Description." (unless (zerop (current-column)) (open-line 1) (forward-line 1)) (cl-flet ((ins (short-space sep) (cond ;; Both available. ((and short long) (insert "**-" short "**") (when arg (insert short-space "*" arg "*")) (insert sep) (insert "**--" long (if arg "=" "") "**") (when arg (insert "\\ \\ *" arg "*"))) ;; TODO: Handle other combinations. (t (error "Could not handle (%S %S %S)" arg short long))))) ;; First line. (insert "[") (ins " " " | ") (insert "]\n") ;; Second line. Leave point at its beginning. (save-excursion (ins " " " \\| ") ;; Add a newline only if necessary. (unless (eolp) (insert "\n"))))) (defun TDM-convert-options (&optional keep-orig) "Grok the options at point and insert formatted ones. If successful, delete the parsed options as well. Prefix arg KEEP-ORIG means don't delete them." (interactive "P") (let* ((p (point)) (triple (TDM-parse-option-triple)) (q (point))) (apply #'TDM-insert-options triple) (unless keep-orig (save-excursion (delete-region p q))))) (defun TDM-recursive-help (command) "Call COMMAND --help and recurse on its subcommands. Subcommands are identified by \"Commands:\" in column 0 in the output. Collect the output in a new buffer *COMMAND --help*, with one page per --help output." (interactive "sCommand: ") (let ((out (get-buffer-create (format "*%s --help*" command)))) (with-current-buffer out (erase-buffer)) (cl-labels ;; visit command ((v (c) (with-temp-buffer (apply #'call-process (car c) nil t nil (append (cdr c) (list "--help"))) (goto-char (point-min)) (when (re-search-forward "^Commands:\n" nil t) (while (looking-at "[ ][ ]\\(\\S +\\)") (let ((sub (match-string 1))) (v (append c (list sub)))) (forward-line 1) (while (looking-at "[ ][ ][ ]") (forward-line 1)))) (let ((s (buffer-string))) (message "c: %s" c) (with-current-buffer out (goto-char (point-min)) (insert "\f\n") (insert "$ " (substring (format "%s" c) 1 -1) "\n") (insert s "\n")))))) (v (list command))) (switch-to-buffer out))) (provide 'TDM) ;;; TDM.el ends here