~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/help_topics.py

  • Committer: Ian Clatworthy
  • Date: 2007-08-14 03:59:22 UTC
  • mto: (2733.1.1 ianc-integration)
  • mto: This revision was merged to the branch mainline in revision 2734.
  • Revision ID: ian.clatworthy@internode.on.net-20070814035922-siavg542cwvkf4r5
Fix pretty doc generation so works for all html docs

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
 
19
19
Help topics are meant to be help for items that aren't commands, but will
20
20
help bzr become fully learnable without referring to a tutorial.
 
21
 
 
22
Limited formatting of help text is permitted to make the text useful
 
23
both within the reference manual (reStructuredText) and on the screen.
 
24
The help text should be reStructuredText with formatting kept to a
 
25
minimum and, in particular, no headings. The onscreen renderer applies
 
26
the following simple rules before rendering the text:
 
27
 
 
28
    1. A '::' appearing on the end of a line is replaced with ':'.
 
29
    2. Lines starting with a ':' have it stripped.
 
30
 
 
31
These rules mean that literal blocks and field lists respectively can
 
32
be used in the help text, producing sensible input to a manual while
 
33
rendering on the screen naturally.
21
34
"""
22
35
 
23
36
from bzrlib import registry
24
37
 
25
38
 
 
39
# Section identifiers (map topics to the right place in the manual)
 
40
SECT_COMMAND = "command"
 
41
SECT_CONCEPT = "concept"
 
42
SECT_HIDDEN =  "hidden"
 
43
SECT_LIST    = "list"
 
44
SECT_PLUGIN  = "plugin"
 
45
 
 
46
 
26
47
class HelpTopicRegistry(registry.Registry):
27
48
    """A Registry customized for handling help topics."""
28
49
 
29
 
    def register(self, topic, detail, summary):
 
50
    def register(self, topic, detail, summary, section=SECT_LIST):
30
51
        """Register a new help topic.
31
52
 
32
53
        :param topic: Name of documentation entry
33
54
        :param detail: Function or string object providing detailed
34
55
            documentation for topic.  Function interface is detail(topic).
35
56
            This should return a text string of the detailed information.
 
57
            See the module documentation for details on help text formatting.
36
58
        :param summary: String providing single-line documentation for topic.
 
59
        :param section: Section in reference manual - see SECT_* identifiers.
37
60
        """
38
 
        # The detail is stored as the 'object' and the 
39
 
        super(HelpTopicRegistry, self).register(topic, detail, info=summary)
 
61
        # The detail is stored as the 'object' and the metadata as the info
 
62
        info=(summary,section)
 
63
        super(HelpTopicRegistry, self).register(topic, detail, info=info)
40
64
 
41
 
    def register_lazy(self, topic, module_name, member_name, summary):
 
65
    def register_lazy(self, topic, module_name, member_name, summary,
 
66
                      section=SECT_LIST):
42
67
        """Register a new help topic, and import the details on demand.
43
68
 
44
69
        :param topic: Name of documentation entry
45
70
        :param module_name: The module to find the detailed help.
46
71
        :param member_name: The member of the module to use for detailed help.
47
72
        :param summary: String providing single-line documentation for topic.
 
73
        :param section: Section in reference manual - see SECT_* identifiers.
48
74
        """
 
75
        # The detail is stored as the 'object' and the metadata as the info
 
76
        info=(summary,section)
49
77
        super(HelpTopicRegistry, self).register_lazy(topic, module_name,
50
 
                                                     member_name, info=summary)
 
78
                                                     member_name, info=info)
51
79
 
52
80
    def get_detail(self, topic):
53
81
        """Get the detailed help on a given topic."""
59
87
 
60
88
    def get_summary(self, topic):
61
89
        """Get the single line summary for the topic."""
62
 
        return self.get_info(topic)
 
90
        info = self.get_info(topic)
 
91
        if info is None:
 
92
            return None
 
93
        else:
 
94
            return info[0]
 
95
 
 
96
    def get_section(self, topic):
 
97
        """Get the section for the topic."""
 
98
        info = self.get_info(topic)
 
99
        if info is None:
 
100
            return None
 
101
        else:
 
102
            return info[1]
 
103
 
 
104
    def get_topics_for_section(self, section):
 
105
        """Get the set of topics in a section."""
 
106
        result = set()
 
107
        for topic in self.keys():
 
108
            if section == self.get_section(topic):
 
109
                result.add(topic)
 
110
        return result
63
111
 
64
112
 
65
113
topic_registry = HelpTopicRegistry()
81
129
 
82
130
 
83
131
def _help_on_revisionspec(name):
84
 
    """Write the summary help for all documented topics to outfile."""
 
132
    """Generate the help for revision specs."""
 
133
    import re
85
134
    import bzrlib.revisionspec
86
135
 
87
136
    out = []
88
 
    out.append("\nRevision prefix specifier:"
89
 
               "\n--------------------------\n")
 
137
    out.append("Revision Identifiers\n")
 
138
    out.append("A revision, or a range bound, can be one of the following.\n")
 
139
    details = []
 
140
    details.append("\nFurther details are given below.\n")
90
141
 
 
142
    # The help text is indented 4 spaces - this re cleans that up below
 
143
    indent_re = re.compile(r'^    ', re.MULTILINE)
91
144
    for i in bzrlib.revisionspec.SPEC_TYPES:
92
145
        doc = i.help_txt
93
146
        if doc == bzrlib.revisionspec.RevisionSpec.help_txt:
94
 
            doc = "N/A\n"
95
 
        while (doc[-2:] == '\n\n' or doc[-1:] == ' '):
96
 
            doc = doc[:-1]
97
 
 
98
 
        out.append("  %s %s\n\n" % (i.prefix, doc))
99
 
 
100
 
    return ''.join(out)
 
147
            summary = "N/A"
 
148
            doc = summary + "\n"
 
149
        else:
 
150
            # Extract out the top line summary from the body and
 
151
            # clean-up the unwanted whitespace
 
152
            summary,doc = doc.split("\n", 1)
 
153
            #doc = indent_re.sub('', doc)
 
154
            while (doc[-2:] == '\n\n' or doc[-1:] == ' '):
 
155
                doc = doc[:-1]
 
156
        
 
157
        # Note: The leading : here are HACKs to get reStructuredText
 
158
        # 'field' formatting - we know that the prefix ends in a ':'.
 
159
        out.append(":%s\n\t%s" % (i.prefix, summary))
 
160
        details.append(":%s\n%s" % (i.prefix, doc))
 
161
 
 
162
    return '\n'.join(out + details)
101
163
 
102
164
 
103
165
def _help_on_transport(name):
122
184
        else:
123
185
            return 0
124
186
 
125
 
    out = []
126
187
    protl = []
127
188
    decl = []
128
189
    protos = transport_list_registry.keys( )
132
193
        if not shorthelp:
133
194
            continue
134
195
        if proto.endswith("://"):
135
 
            protl.extend(add_string(proto, shorthelp, 79))
 
196
            protl.append(add_string(proto, shorthelp, 79))
136
197
        else:
137
 
            decl.extend(add_string(proto, shorthelp, 79))
138
 
 
139
 
 
140
 
    out = "\nSupported URL prefix\n--------------------\n" + \
141
 
            ''.join(protl)
 
198
            decl.append(add_string(proto, shorthelp, 79))
 
199
 
 
200
 
 
201
    out = "URL Identifiers\n\n" + \
 
202
            "Supported URL prefixes::\n\n  " + \
 
203
            '  '.join(protl)
142
204
 
143
205
    if len(decl):
144
 
        out += "\nSupported modifiers\n-------------------\n" + \
145
 
            ''.join(decl)
 
206
        out += "\nSupported modifiers::\n\n  " + \
 
207
            '  '.join(decl)
146
208
 
147
209
    return out
148
210
 
149
211
 
150
 
_basic_help= \
 
212
_basic_help = \
151
213
"""Bazaar -- a free distributed version-control tool
152
214
http://bazaar-vcs.org/
153
215
 
174
236
"""
175
237
 
176
238
 
177
 
_global_options =\
 
239
_global_options = \
178
240
"""Global Options
179
241
 
180
242
These options may be used with any command, and may appear in front of any
194
256
--lsprof       Profile execution using the lsprof profiler
195
257
--lsprof-file  Profile execution using the lsprof profiler, and write the
196
258
               results to a specified file.  If the filename ends with ".txt",
197
 
               text format will be used.  If the filename ends with
198
 
               ".callgrind", output will be formatted for use with KCacheGrind.
199
 
               Otherwise, the output will be a pickle.
 
259
               text format will be used.  If the filename either starts with
 
260
               "callgrind.out" or end with ".callgrind", the output will be
 
261
               formatted for use with KCacheGrind. Otherwise, the output
 
262
               will be a pickle.
200
263
 
201
264
See doc/developers/profiling.txt for more information on profiling.
202
265
 
267
330
would like to convert your heavy checkout into a normal branch so that every
268
331
commit is local, you can use the "unbind" command.
269
332
 
270
 
Related commands:
 
333
Related commands::
271
334
 
272
335
  checkout    Create a checkout. Pass --lightweight to get a lightweight
273
336
              checkout
317
380
the branches will not have working trees pass the '--no-trees' option to
318
381
'init-repository'.
319
382
 
320
 
Related commands:
 
383
Related commands::
321
384
 
322
385
  init-repository   Create a shared repository. Use --no-trees to create one
323
386
                    in which new branches won't get a working tree.
357
420
is also a 'push-and-update' plugin that automates running 'bzr update' via SSH
358
421
after each push.
359
422
 
360
 
Useful commands:
 
423
Useful commands::
361
424
 
362
425
  checkout     Create a working tree when a branch does not have one.
363
426
  remove-tree  Removes the working tree from a branch when it is safe to do so.
369
432
"""Status Flags
370
433
 
371
434
Status flags are used to summarise changes to the working tree in a concise
372
 
manner.  They are in the form:
 
435
manner.  They are in the form::
 
436
 
373
437
   xxx   <filename>
 
438
 
374
439
where the columns' meanings are as follows.
375
440
 
376
 
Column 1: versioning / renames
 
441
Column 1 - versioning/renames::
 
442
 
377
443
  + File versioned
378
444
  - File unversioned
379
445
  R File renamed
381
447
  C File has conflicts
382
448
  P Entry for a pending merge (not a file)
383
449
 
384
 
Column 2: Contents
 
450
Column 2 - contents::
 
451
 
385
452
  N File created
386
453
  D File deleted
387
454
  K File kind changed
388
455
  M File modified
389
456
 
390
 
Column 3: Execute
 
457
Column 3 - execute::
 
458
 
391
459
  * The execute bit was changed
392
460
"""
393
461
 
394
462
 
 
463
_env_variables = \
 
464
"""Environment Variables
 
465
 
 
466
================ =================================================================
 
467
BZRPATH          Path where bzr is to look for shell plugin external commands.
 
468
BZR_EMAIL        E-Mail address of the user. Overrides EMAIL.
 
469
EMAIL            E-Mail address of the user.
 
470
BZR_EDITOR       Editor for editing commit messages. Overrides EDITOR.
 
471
EDITOR           Editor for editing commit messages.
 
472
BZR_PLUGIN_PATH  Paths where bzr should look for plugins.
 
473
BZR_HOME         Directory holding .bazaar config dir. Overrides HOME.
 
474
BZR_HOME (Win32) Directory holding bazaar config dir. Overrides APPDATA and HOME.
 
475
================ =================================================================
 
476
"""
 
477
 
 
478
 
 
479
_files = \
 
480
r"""Files
 
481
 
 
482
:On Linux:   ~/.bazaar/bazaar.conf
 
483
:On Windows: C:\\Documents and Settings\\username\\Application Data\\bazaar\\2.0\\bazaar.conf
 
484
 
 
485
Contains the user's default configuration. The section ``[DEFAULT]`` is
 
486
used to define general configuration that will be applied everywhere.
 
487
The section ``[ALIASES]`` can be used to create command aliases for
 
488
commonly used options.
 
489
 
 
490
A typical config file might look something like::
 
491
 
 
492
  [DEFAULT]
 
493
  email=John Doe <jdoe@isp.com>
 
494
 
 
495
  [ALIASES]
 
496
  commit = commit --strict
 
497
  log10 = log --short -r -10..-1
 
498
"""
 
499
 
 
500
 
395
501
topic_registry.register("revisionspec", _help_on_revisionspec,
396
502
                        "Explain how to use --revision")
397
 
topic_registry.register('basic', _basic_help, "Basic commands")
398
 
topic_registry.register('topics', _help_on_topics, "Topics list")
 
503
topic_registry.register('basic', _basic_help, "Basic commands", SECT_HIDDEN)
 
504
topic_registry.register('topics', _help_on_topics, "Topics list", SECT_HIDDEN)
399
505
def get_format_topic(topic):
400
506
    from bzrlib import bzrdir
401
 
    return bzrdir.format_registry.help_topic(topic)
 
507
    return "Storage Formats\n\n" + bzrdir.format_registry.help_topic(topic)
402
508
topic_registry.register('formats', get_format_topic, 'Directory formats')
403
509
topic_registry.register('global-options', _global_options,
404
510
                        'Options that can be used with any command')
405
511
topic_registry.register('checkouts', _checkouts,
406
 
                        'Information on what a checkout is')
 
512
                        'Information on what a checkout is', SECT_CONCEPT)
407
513
topic_registry.register('urlspec', _help_on_transport,
408
514
                        "Supported transport protocols")
409
515
topic_registry.register('status-flags', _status_flags,
410
516
                        "Help on status flags")
411
517
def get_bugs_topic(topic):
412
518
    from bzrlib import bugtracker
413
 
    return bugtracker.tracker_registry.help_topic(topic)
 
519
    return "Bug Trackers\n\n" + bugtracker.tracker_registry.help_topic(topic)
414
520
topic_registry.register('bugs', get_bugs_topic, 'Bug tracker support')
415
521
topic_registry.register('repositories', _repositories,
416
 
                        'Basic information on shared repositories.')
 
522
                        'Basic information on shared repositories.',
 
523
                        SECT_CONCEPT)
417
524
topic_registry.register('working-trees', _working_trees,
418
 
                        'Information on working trees')
 
525
                        'Information on working trees', SECT_CONCEPT)
 
526
topic_registry.register('env-variables', _env_variables,
 
527
                        'Environment variable names and values')
 
528
topic_registry.register('files', _files,
 
529
                        'Information on configuration and log files')
419
530
 
420
531
 
421
532
class HelpTopicIndex(object):
453
564
        """
454
565
        self.topic = topic
455
566
 
456
 
    def get_help_text(self, additional_see_also=None):
 
567
    def get_help_text(self, additional_see_also=None, plain=True):
457
568
        """Return a string with the help for this topic.
458
569
 
459
570
        :param additional_see_also: Additional help topics to be
460
571
            cross-referenced.
 
572
        :param plain: if False, raw help (reStructuredText) is
 
573
            returned instead of plain text.
461
574
        """
462
575
        result = topic_registry.get_detail(self.topic)
463
576
        # there is code duplicated here and in bzrlib/plugin.py's 
468
581
        else:
469
582
            see_also = None
470
583
        if see_also:
471
 
            result += '\nSee also: '
 
584
            result += '\n:See also: '
472
585
            result += ', '.join(see_also)
473
586
            result += '\n'
 
587
        if plain:
 
588
            result = help_as_plain_text(result)
474
589
        return result
475
590
 
476
591
    def get_help_topic(self):
477
592
        """Return the help topic this can be found under."""
478
593
        return self.topic
479
594
 
 
595
 
 
596
def help_as_plain_text(text):
 
597
    """Minimal converter of reStructuredText to plain text."""
 
598
    lines = text.splitlines()
 
599
    result = []
 
600
    for line in lines:
 
601
        if line.startswith(':'):
 
602
            line = line[1:]
 
603
        elif line.endswith('::'):
 
604
            line = line[:-1]
 
605
        result.append(line)
 
606
    return "\n".join(result) + "\n"