~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/help_topics.py

  • Committer: Martin Pool
  • Date: 2007-09-14 06:31:28 UTC
  • mfrom: (2822 +trunk)
  • mto: This revision was merged to the branch mainline in revision 2823.
  • Revision ID: mbp@sourcefrog.net-20070914063128-0p7mh6zfb4pzdg9p
merge trunk

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
181
 
command.  (e.g. "bzr --quiet help").
182
 
 
183
 
--quiet        Suppress informational output; only print errors and warnings
184
 
--version      Print the version number
185
 
 
186
 
--no-aliases   Do not process command aliases when running this command
 
243
command.  (e.g. "bzr --profile help").
 
244
 
 
245
--version      Print the version number. Must be supplied before the command.
 
246
--no-aliases   Do not process command aliases when running this command.
187
247
--builtin      Use the built-in version of a command, not the plugin version.
188
 
               This does not suppress other plugin effects
189
 
--no-plugins   Do not process any plugins
 
248
               This does not suppress other plugin effects.
 
249
--no-plugins   Do not process any plugins.
190
250
 
191
 
-Derror        Instead of normal error handling, always print a traceback on
192
 
               error.
193
 
--profile      Profile execution using the hotshot profiler
194
 
--lsprof       Profile execution using the lsprof profiler
 
251
--profile      Profile execution using the hotshot profiler.
 
252
--lsprof       Profile execution using the lsprof profiler.
195
253
--lsprof-file  Profile execution using the lsprof profiler, and write the
196
254
               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.
 
255
               text format will be used.  If the filename either starts with
 
256
               "callgrind.out" or end with ".callgrind", the output will be
 
257
               formatted for use with KCacheGrind. Otherwise, the output
 
258
               will be a pickle.
200
259
 
201
260
See doc/developers/profiling.txt for more information on profiling.
202
 
 
203
 
Note: --version must be supplied before any command.
204
 
"""
 
261
A number of debug flags are also available to assist troubleshooting and
 
262
development.
 
263
 
 
264
-Derror        Instead of normal error handling, always print a traceback on
 
265
               error.
 
266
-Devil         Capture call sites that do expensive or badly-scaling
 
267
               operations.
 
268
-Dhooks        Trace hook execution.
 
269
-Dhpss         Trace smart protocol requests and responses.
 
270
-Dindex        Trace major index operations.
 
271
-Dlock         Trace when lockdir locks are taken or released.
 
272
"""
 
273
 
 
274
_standard_options = \
 
275
"""Standard Options
 
276
 
 
277
Standard options are legal for all commands.
 
278
      
 
279
--help, -h     Show help message.
 
280
--verbose, -v  Display more information.
 
281
--quiet, -q    Only display errors and warnings.
 
282
 
 
283
Unlike global options, standard options can be used in aliases.
 
284
"""
 
285
 
205
286
 
206
287
_checkouts = \
207
288
"""Checkouts
267
348
would like to convert your heavy checkout into a normal branch so that every
268
349
commit is local, you can use the "unbind" command.
269
350
 
270
 
Related commands:
 
351
Related commands::
271
352
 
272
353
  checkout    Create a checkout. Pass --lightweight to get a lightweight
273
354
              checkout
317
398
the branches will not have working trees pass the '--no-trees' option to
318
399
'init-repository'.
319
400
 
320
 
Related commands:
 
401
Related commands::
321
402
 
322
403
  init-repository   Create a shared repository. Use --no-trees to create one
323
404
                    in which new branches won't get a working tree.
357
438
is also a 'push-and-update' plugin that automates running 'bzr update' via SSH
358
439
after each push.
359
440
 
360
 
Useful commands:
 
441
Useful commands::
361
442
 
362
443
  checkout     Create a working tree when a branch does not have one.
363
444
  remove-tree  Removes the working tree from a branch when it is safe to do so.
365
446
               this will update the tree to match the branch.
366
447
"""
367
448
 
 
449
 
 
450
_branches = \
 
451
"""Branches
 
452
 
 
453
A branch consists of the state of a project, including all of its
 
454
history. All branches have a repository associated (which is where the
 
455
branch history is stored), but multiple branches may share the same
 
456
repository (a shared repository). Branches can be copied and merged.
 
457
 
 
458
Related commands::
 
459
 
 
460
  init    Make a directory into a versioned branch.
 
461
  branch  Create a new copy of a branch.
 
462
  merge   Perform a three-way merge.
 
463
"""
 
464
 
 
465
 
 
466
_standalone_trees = \
 
467
"""Standalone Trees
 
468
 
 
469
A standalone tree is a working tree with an associated repository. It
 
470
is an independently usable branch, with no dependencies on any other.
 
471
Creating a standalone tree (via bzr init) is the quickest way to put
 
472
an existing project under version control.
 
473
 
 
474
Related Commands::
 
475
 
 
476
  init    Make a directory into a versioned branch.
 
477
"""
 
478
 
 
479
 
368
480
_status_flags = \
369
481
"""Status Flags
370
482
 
371
483
Status flags are used to summarise changes to the working tree in a concise
372
 
manner.  They are in the form:
 
484
manner.  They are in the form::
 
485
 
373
486
   xxx   <filename>
 
487
 
374
488
where the columns' meanings are as follows.
375
489
 
376
 
Column 1: versioning / renames
 
490
Column 1 - versioning/renames::
 
491
 
377
492
  + File versioned
378
493
  - File unversioned
379
494
  R File renamed
381
496
  C File has conflicts
382
497
  P Entry for a pending merge (not a file)
383
498
 
384
 
Column 2: Contents
 
499
Column 2 - contents::
 
500
 
385
501
  N File created
386
502
  D File deleted
387
503
  K File kind changed
388
504
  M File modified
389
505
 
390
 
Column 3: Execute
 
506
Column 3 - execute::
 
507
 
391
508
  * The execute bit was changed
392
509
"""
393
510
 
394
511
 
 
512
_env_variables = \
 
513
"""Environment Variables
 
514
 
 
515
================ =================================================================
 
516
BZRPATH          Path where bzr is to look for shell plugin external commands.
 
517
BZR_EMAIL        E-Mail address of the user. Overrides EMAIL.
 
518
EMAIL            E-Mail address of the user.
 
519
BZR_EDITOR       Editor for editing commit messages. Overrides EDITOR.
 
520
EDITOR           Editor for editing commit messages.
 
521
BZR_PLUGIN_PATH  Paths where bzr should look for plugins.
 
522
BZR_HOME         Directory holding .bazaar config dir. Overrides HOME.
 
523
BZR_HOME (Win32) Directory holding bazaar config dir. Overrides APPDATA and HOME.
 
524
================ =================================================================
 
525
"""
 
526
 
 
527
 
 
528
_files = \
 
529
r"""Files
 
530
 
 
531
:On Linux:   ~/.bazaar/bazaar.conf
 
532
:On Windows: C:\\Documents and Settings\\username\\Application Data\\bazaar\\2.0\\bazaar.conf
 
533
 
 
534
Contains the user's default configuration. The section ``[DEFAULT]`` is
 
535
used to define general configuration that will be applied everywhere.
 
536
The section ``[ALIASES]`` can be used to create command aliases for
 
537
commonly used options.
 
538
 
 
539
A typical config file might look something like::
 
540
 
 
541
  [DEFAULT]
 
542
  email=John Doe <jdoe@isp.com>
 
543
 
 
544
  [ALIASES]
 
545
  commit = commit --strict
 
546
  log10 = log --short -r -10..-1
 
547
"""
 
548
 
 
549
 
 
550
# Register help topics
395
551
topic_registry.register("revisionspec", _help_on_revisionspec,
396
552
                        "Explain how to use --revision")
397
 
topic_registry.register('basic', _basic_help, "Basic commands")
398
 
topic_registry.register('topics', _help_on_topics, "Topics list")
 
553
topic_registry.register('basic', _basic_help, "Basic commands", SECT_HIDDEN)
 
554
topic_registry.register('topics', _help_on_topics, "Topics list", SECT_HIDDEN)
399
555
def get_format_topic(topic):
400
556
    from bzrlib import bzrdir
401
 
    return bzrdir.format_registry.help_topic(topic)
 
557
    return "Storage Formats\n\n" + bzrdir.format_registry.help_topic(topic)
402
558
topic_registry.register('formats', get_format_topic, 'Directory formats')
 
559
topic_registry.register('standard-options', _standard_options,
 
560
                        'Options that can be used with any command')
403
561
topic_registry.register('global-options', _global_options,
404
 
                        'Options that can be used with any command')
405
 
topic_registry.register('checkouts', _checkouts,
406
 
                        'Information on what a checkout is')
 
562
                    'Options that control how Bazaar runs')
407
563
topic_registry.register('urlspec', _help_on_transport,
408
564
                        "Supported transport protocols")
409
565
topic_registry.register('status-flags', _status_flags,
410
566
                        "Help on status flags")
411
567
def get_bugs_topic(topic):
412
568
    from bzrlib import bugtracker
413
 
    return bugtracker.tracker_registry.help_topic(topic)
 
569
    return "Bug Trackers\n\n" + bugtracker.tracker_registry.help_topic(topic)
414
570
topic_registry.register('bugs', get_bugs_topic, 'Bug tracker support')
 
571
topic_registry.register('env-variables', _env_variables,
 
572
                        'Environment variable names and values')
 
573
topic_registry.register('files', _files,
 
574
                        'Information on configuration and log files')
 
575
 
 
576
 
 
577
# Register concept topics.
 
578
# Note that we might choose to remove these from the online help in the
 
579
# future or implement them via loading content from files. In the meantime,
 
580
# please keep them concise.
 
581
topic_registry.register('branches', _branches,
 
582
                        'Information on what a branch is', SECT_CONCEPT)
 
583
topic_registry.register('checkouts', _checkouts,
 
584
                        'Information on what a checkout is', SECT_CONCEPT)
415
585
topic_registry.register('repositories', _repositories,
416
 
                        'Basic information on shared repositories.')
 
586
                        'Basic information on shared repositories.',
 
587
                        SECT_CONCEPT)
 
588
topic_registry.register('standalone-trees', _standalone_trees,
 
589
                        'Information on what a standalone tree is',
 
590
                        SECT_CONCEPT)
417
591
topic_registry.register('working-trees', _working_trees,
418
 
                        'Information on working trees')
 
592
                        'Information on working trees', SECT_CONCEPT)
419
593
 
420
594
 
421
595
class HelpTopicIndex(object):
453
627
        """
454
628
        self.topic = topic
455
629
 
456
 
    def get_help_text(self, additional_see_also=None):
 
630
    def get_help_text(self, additional_see_also=None, plain=True):
457
631
        """Return a string with the help for this topic.
458
632
 
459
633
        :param additional_see_also: Additional help topics to be
460
634
            cross-referenced.
 
635
        :param plain: if False, raw help (reStructuredText) is
 
636
            returned instead of plain text.
461
637
        """
462
638
        result = topic_registry.get_detail(self.topic)
463
639
        # there is code duplicated here and in bzrlib/plugin.py's 
468
644
        else:
469
645
            see_also = None
470
646
        if see_also:
471
 
            result += '\nSee also: '
 
647
            result += '\n:See also: '
472
648
            result += ', '.join(see_also)
473
649
            result += '\n'
 
650
        if plain:
 
651
            result = help_as_plain_text(result)
474
652
        return result
475
653
 
476
654
    def get_help_topic(self):
477
655
        """Return the help topic this can be found under."""
478
656
        return self.topic
479
657
 
 
658
 
 
659
def help_as_plain_text(text):
 
660
    """Minimal converter of reStructuredText to plain text."""
 
661
    lines = text.splitlines()
 
662
    result = []
 
663
    for line in lines:
 
664
        if line.startswith(':'):
 
665
            line = line[1:]
 
666
        elif line.endswith('::'):
 
667
            line = line[:-1]
 
668
        result.append(line)
 
669
    return "\n".join(result) + "\n"