summaryrefslogtreecommitdiff
path: root/manpages/TDM.el
blob: a58fb1c8afc00123594b44f8b18bd14a87981490 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
;;; 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
;; <http://www.gnu.org/licenses/>.
;;
;; Author: Thien-Thi Nguyen <ttn@gnu.org>

;;; 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 <FOO> 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