Files @ r38:fa115af9c367
Branch filter:

Location: public/ws-vacation/doc/tools/ws_sh2rst.py

ws
README.txt: minor fix
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright (C) 2011, Wolfgang Scherer, <Wolfgang.Scherer at gmx.de>
# Sponsored by WIEDENMANN SEILE GMBH, http://www.wiedenmannseile.de
#
# This file is part of Wiedenmann Applications.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program 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
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>,
# or write to <Wolfgang.Scherer at gmx.de>
"""\
sh2rst.py - sh(1) scripts to reStructuredText

usage: sh2rst.py [OPTIONS] []

OPTIONS
  -t, --test     run doctests
  -v, --verbose  verbose test output
  -h, --help     display this help message
"""

# --------------------------------------------------
# |||:sec:||| CONFIGURATION
# --------------------------------------------------

import sys
import os
import re

##
# reStructuredText header.
rst_header = """\
.. -*- rst -*-
.. role:: rem(span)
   :format: ''
"""

rst_contents = """
.. contents::
"""

rst_contents_before_header = False

# --------------------------------------------------
# |||:sec:||| CLASSES
# --------------------------------------------------

# --------------------------------------------------
# |||:sec:||| FUNCTIONS
# --------------------------------------------------

def rem( str_, lead_ws = False ): # ||:fnc:||
    if lead_ws:
        return ''.join(("\\ :rem:`", str_, "`"))
    return ''.join((":rem:`", str_, "`\\ "))

def sec(str_ = "|||" ":sec:|||", plain = False): # ||:fnc:||
    if plain:
        return str_
    return rem(str_)

# state variables
_in_body = False
_pend_nl = False

def header(title):               # ||:fnc:||
    global rst_header
    global rst_contents
    sline = "{0} {1}".format(sec(), title)
    ouline = "#" * len(sline)
    ousec = "-" * 50
    if rst_contents_before_header:
        first = ''.join((rst_header, rst_contents))
        second = ""
    else:
        first = rst_header
        second = rst_contents
        
    hd = "\n".join((
            first,
            ouline, sline, ouline,
            second,
            ousec, 'SYNOPSIS', ousec,
            ))
    rst_header = ""
    rst_contents = ""
    return hd

def outline(line=''):            # ||:fnc:||
    global _in_body
    global _pend_nl
    if not line:
        if _in_body:
            _pend_nl = True
        return
    elif not _in_body:
        print(header(line))
        _in_body = True
        _pend_nl = True
        return
    if _pend_nl:
        print('')
        _pend_nl = False
    print line

def run():                      # ||:fnc:||
    global _in_body
    global _pend_nl
    files = sys.argv[1:]
    if len(files) > 1:
        global rst_contents_before_header
        rst_contents_before_header = True
    if not files:
        files = ('-')
    # handle all files
    for file_ in files:
        if file_ == '-':
            fn = '<stdin>'
            fh = sys.stdin
            do_close = False
        else:
            fn = os.path.basename( file_ )
            fh = open(file_, "rb")
            do_close = True
        contents = fh.read()
        if do_close:
            fh.close()
        lines = re.split('[ \t\r]*\n', contents)
        _in_body = False
        in_descr = True
        lineno = 0
        # handle all lines
        for line in lines:
            lineno += 1
            # stop on \f
            if line.find('\f') >= 0:
                break
            line = line.rstrip()
            if not line:
                outline()
                continue
            mo = re.match('^# ?(.*)', line)

            # comment line
            if mo:
                if not in_descr:
                    outline()
                    in_descr = True
                line = mo.groups()[ 0 ]
                if not line:
                    outline()
                    continue
                # she-bang
                if line.startswith( '!/' ):
                    continue
                # emacs definition/python coding
                if line.startswith( '-*-' ):
                    continue
                # double comment
                if line.startswith( '#' ):
                    continue
                # handle tags
                first = True
                pre = []
                while True:
                    #                 1      2    3      4    5
                    mo = re.match('''^([^|]*)(\|+)(:[^:]+:)(\|+)(.*)''',line)
                    if mo:
                        groups = mo.groups()
                        # translate section tags
                        pre_tag = groups[0]
                        post_tag = groups[4]
                        if first:
                            if not pre_tag and not post_tag:
                                line = ''
                                break
                            pre.append(pre_tag)
                            pre.append(sec(''.join((groups[1], groups[2], groups[3]))))
                            post_tag = post_tag.lstrip()
                            first = False
                        else:
                            pre.append(pre_tag)
                            pre.append(''.join(('\\', groups[1], groups[2], groups[3])))
                        line = post_tag
                    else:
                        break
                pre.append(line)
                line = ''.join(pre)
                outline(line)

            # skip special marker line
            elif line.startswith(': # script help'):
                continue

            # print code lines as block quote
            else:
                if in_descr:
                    outline()
                    outline("::")
                    outline()
                    in_descr = False
                outline('  {0:03d}  {1}'.format(lineno, line))

# --------------------------------------------------
# |||:sec:||| MAIN
# --------------------------------------------------

##
# Verbosity flag.
_verbose = False

##
# Debug flag.
_debug = False

def main( argv ):               # ||:fnc:||
    """Generic main function.

    :return: exit status
    :param argv: command line arguments (defaults to sys.argv)
    """
    import getopt
    optstr = ""; long_opts = []
    optstr += "h"; long_opts.append( "help" )
    global _verbose
    optstr += "v"; long_opts.append( "verbose" )
    global _debug
    optstr += "d"; long_opts.append( "debug" )
    _opt_test = False
    optstr += "t"; long_opts.append( "test" )
    # |:sec:| options
    try:
        opts, args = getopt.gnu_getopt( argv[ 1: ], optstr, long_opts )
    except getopt.GetoptError as err:
        sys.stderr.write( "".join(( str( err ), "\n" )))
        sys.stderr.write( __doc__ )
        sys.exit(1)
    for opt, arg in opts:
        if opt in ( "-h", "--help" ):
            sys.stdout.write( __doc__ )
            sys.exit()
        # |:sec:| options
        elif opt in ( "-v", "--verbose" ):
            _verbose = True
        elif opt in ( "-d", "--debug" ):
            _verbose = True
            _debug = True
        elif opt in ( "-t", "--test" ):
            _opt_test = True
        else:
            assert False, "unhandled option"
    if _opt_test:
        import doctest
        doctest.testmod( verbose = _verbose )
        sys.exit()
    # |:here:|
    if _debug:
        cmd_line = sys.argv
        sys.stderr.write( "# {1:<{0}s}: [{2!s}]\n".format(
                dbg_fwid if 'dbg_fwid' in globals() else 15, 'cmd_line',
                cmd_line ))
    del( sys.argv[ 1: ])
    sys.argv.extend( args )
    run()

if __name__ == "__main__":
    sys.argv.insert( 1, '--debug' ) # |:debug:|
    main( sys.argv )
    sys.exit()

# |:here:|
#
# :ide-menu: Emacs IDE Main Menu - Buffer @BUFFER@
# . M-x `eIDE-menu' (eIDE-menu "z")

# :ide: SNIP: insert PROG-PATH
# . (snip-insert-mode "py_prog-path" nil t)

# :ide: CSCOPE ON
# . (cscope-minor-mode)

# :ide: CSCOPE OFF
# . (cscope-minor-mode (quote ( nil )))

# :ide: COMPILE: Run with --help
# . (progn (save-buffer) (compile (concat "python ./" (file-name-nondirectory (buffer-file-name)) " --help")))

# :ide: COMPILE: Run with --test
# . (progn (save-buffer) (compile (concat "python ./" (file-name-nondirectory (buffer-file-name)) " --test")))

# :ide: COMPILE: Run with --test --verbose
# . (progn (save-buffer) (compile (concat "python ./" (file-name-nondirectory (buffer-file-name)) " --test --verbose")))

# :ide: INFO: Python Documentation
# . (let ((ref-buffer "*w3m*")) (if (get-buffer ref-buffer) (display-buffer ref-buffer t)) (other-window 1) (w3m-goto-url "http://docs.python.org/index.html" nil nil))

# :ide: INFO: Python Reference
# . (let ((ref-buffer "*python-ref*")) (if (not (get-buffer ref-buffer)) (shell-command (concat "w3m -dump -cols " (number-to-string (1- (window-width))) " 'http://rgruet.free.fr/PQR26/PQR2.6.html'") ref-buffer) (display-buffer ref-buffer t)))

# :ide: COMPILE: Run w/o args
# . (progn (save-buffer) (compile (concat "python ./" (file-name-nondirectory (buffer-file-name)) " ")))

# :ide: COMPILE: Run with /usr/local/bin/hg-status-all.sh
# . (progn (save-buffer) (compile (concat "python ./" (file-name-nondirectory (buffer-file-name)) " /usr/local/bin/hg-status-all.sh | tee hg-status-all.txt; rst2html.py hg-status-all.txt >hg-status-all.html")))

# :ide: COMPILE: Run with /usr/local/bin/hg-status-all.sh + /home/ws/develop/util/gen-tags/gen_etags.sh
# . (let ((f0 (file-name-nondirectory (buffer-file-name))) (f1 "/usr/local/bin/hg-status-all.sh") (f2 "/home/ws/develop/util/gen-tags/gen_etags.sh") (ob "scripts")) (save-buffer) (compile (concat "python ./" f0 " " f1 " " f2 " | tee " ob ".txt; rst2html.py " ob ".txt >" ob ".html")))

#
# Local Variables:
# mode: python
# comment-start: "#"
# comment-start-skip: "#+"
# comment-column: 0
# End: