taler-docs

Documentation for GNU Taler components, APIs and protocols
Log | Files | Refs | README | LICENSE

TDM.el (6482B)


      1 ;;; TDM.el --- editing Taler docs.git/manpages/*   -*- lexical-binding: t -*-
      2 
      3 ;; Copyright (C) 2021, 2022 Taler Systems SA
      4 ;;
      5 ;; This file is part of GNU TALER.
      6 ;;
      7 ;; TALER is free software; you can redistribute it and/or modify it
      8 ;; under the terms of the GNU Affero General Public License as
      9 ;; published by the Free Software Foundation; either version 2.1,
     10 ;; or (at your option) any later version.
     11 ;;
     12 ;; TALER is distributed in the hope that it will be useful, but
     13 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
     14 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 ;; GNU Affero General Public License for more details.
     16 ;;
     17 ;; You should have received a copy of the GNU Affero General Public
     18 ;; License along with TALER; see the file COPYING.  If not, see
     19 ;; <http://www.gnu.org/licenses/>.
     20 ;;
     21 ;; Author: Thien-Thi Nguyen <ttn@gnu.org>
     22 
     23 ;;; Commentary:
     24 
     25 ;; This library currently provides two commands: ‘TDM-convert-options’
     26 ;; and ‘TDM-recursive-help’.
     27 ;;
     28 ;; * ‘TDM-convert-options’
     29 ;; The intended workflow is simple:
     30 ;;  - Create a new file from template.
     31 ;;  - Do the <FOO> substitutions / deletions as necessary.
     32 ;;  - Split the window, one half for Synopsis, one for Description.
     33 ;;  - Do ‘COMMAND --help’ and copy the portion of its output that
     34 ;;    describes the options into the buffer in the Synopsis section.
     35 ;;  + Place point at bol of an option and call ‘TDM-convert-options’.
     36 ;;    (Personally, I locally bind this to ‘C-c C-o’.)
     37 ;;  - Set mark at point and move point to the end of the
     38 ;;    description text (for that option).
     39 ;;  - Kill the region (with ‘C-w’).
     40 ;;  - Switch to the other window, find a suitable place, and
     41 ;;    yank (with ‘C-y’) the text there.
     42 ;;  - Edit the description as necessary.
     43 ;;  - Loop from "+" until finished.
     44 ;;
     45 ;; At the end, you may have to delete some extra blank lines
     46 ;; in the Synopsis section.
     47 ;;
     48 ;; ‘TDM-convert-options’ takes a prefix arg, which inhibits the
     49 ;; deletion of the original (--help output) text.  This can be
     50 ;; useful if you don't trust (yet :-D) the conversion process.
     51 ;;
     52 ;; There are a couple TODO items, which point to situations that
     53 ;; have not yet arisen in practice, but that might theoretically
     54 ;; bother us in the future.
     55 ;;
     56 ;; * ‘TDM-recursive-help’
     57 ;; This command is intended for libeufin programs, specifically
     58 ;; libeufin-sandbox, libeufin-nexus, and libeufin-cli.  However,
     59 ;; it should work with any Java program that uses clikt, or any
     60 ;; Python program that uses click, for its command-line handling.
     61 ;;
     62 ;; You can obtain the --help output (recursively) in a buffer
     63 ;; and write it to a file for further analysis / processing.
     64 
     65 ;;; Code:
     66 
     67 (require 'cl-lib)
     68 
     69 (defun TDM-parse-option-triple ()
     70   "Return a triple formed by parsing option text at point.
     71 The triple has the form (ARG SHORT LONG), where each element
     72 can be either a string or ‘nil’.
     73 
     74 Signal error if parsing fails.
     75 Leave point after the end of the parsed text."
     76   (cl-flet ((peer (regexp)
     77                   (re-search-forward regexp (line-end-position) t)))
     78     (cond
     79      ;; Full form: (ARG SHORT LONG).
     80      ((peer " *-\\(.\\), --\\([^=\n]+\\)=\\(\\S +\\)")
     81       (mapcar #'match-string-no-properties (list 3 1 2)))
     82      ;; No argument: (nil SHORT LONG).
     83      ((peer " *-\\(.\\), --\\(\\S +\\)")
     84       (list nil
     85             (match-string-no-properties 1)
     86             (match-string-no-properties 2)))
     87      ;; TODO: Handle other combinations.
     88      (t
     89       (error "Could not parse option text")))))
     90 
     91 (defun TDM-insert-options (arg short long)
     92   "Insert formatted options, twice (on two lines).
     93 The first is for the Synopsis section, the second for Description."
     94   (unless (zerop (current-column))
     95     (open-line 1)
     96     (forward-line 1))
     97   (cl-flet ((ins (short-space sep)
     98                  (cond
     99                   ;; Both available.
    100                   ((and short long)
    101                    (insert "**-" short "**")
    102                    (when arg
    103                      (insert short-space "*" arg "*"))
    104                    (insert sep)
    105                    (insert "**--" long (if arg "=" "") "**")
    106                    (when arg
    107                      (insert "\\ \\ *" arg "*")))
    108                   ;; TODO: Handle other combinations.
    109                   (t
    110                    (error "Could not handle (%S %S %S)"
    111                           arg short long)))))
    112     ;; First line.
    113     (insert "[")
    114     (ins " " " | ")
    115     (insert "]\n")
    116     ;; Second line.  Leave point at its beginning.
    117     (save-excursion
    118       (ins " " " \\| ")
    119       ;; Add a newline only if necessary.
    120       (unless (eolp)
    121         (insert "\n")))))
    122 
    123 (defun TDM-convert-options (&optional keep-orig)
    124   "Grok the options at point and insert formatted ones.
    125 If successful, delete the parsed options as well.
    126 Prefix arg KEEP-ORIG means don't delete them."
    127   (interactive "P")
    128   (let* ((p (point))
    129          (triple (TDM-parse-option-triple))
    130          (q (point)))
    131     (apply #'TDM-insert-options triple)
    132     (unless keep-orig
    133       (save-excursion
    134         (delete-region p q)))))
    135 
    136 (defun TDM-recursive-help (command)
    137   "Call COMMAND --help and recurse on its subcommands.
    138 Subcommands are identified by \"Commands:\" in column 0
    139 in the output.
    140 
    141 Collect the output in a new buffer *COMMAND --help*,
    142 with one page per --help output."
    143   (interactive "sCommand: ")
    144   (let ((out (get-buffer-create (format "*%s --help*" command))))
    145     (with-current-buffer out
    146       (erase-buffer))
    147     (cl-labels
    148         ;; visit command
    149         ((v (c) (with-temp-buffer
    150                   (apply #'call-process (car c) nil t nil
    151                          (append (cdr c) (list "--help")))
    152                   (goto-char (point-min))
    153                   (when (re-search-forward "^Commands:\n" nil t)
    154                     (while (looking-at "[ ][ ]\\(\\S +\\)")
    155                       (let ((sub (match-string 1)))
    156                         (v (append c (list sub))))
    157                       (forward-line 1)
    158                       (while (looking-at "[ ][ ][ ]")
    159                         (forward-line 1))))
    160                   (let ((s (buffer-string)))
    161                     (message "c: %s" c)
    162                     (with-current-buffer out
    163                       (goto-char (point-min))
    164                       (insert "\f\n")
    165                       (insert "$ " (substring (format "%s" c) 1 -1) "\n")
    166                       (insert s "\n"))))))
    167       (v (list command)))
    168     (switch-to-buffer out)))
    169 
    170 (provide 'TDM)
    171 
    172 ;;; TDM.el ends here