17 ) |
17 ) |
18 |
18 |
19 class exthelper(object): |
19 class exthelper(object): |
20 """Helper for modular extension setup |
20 """Helper for modular extension setup |
21 |
21 |
22 A single helper should be instantiated for each extension. Helper |
22 A single helper should be instantiated for each module of an |
23 methods are then used as decorators for various purpose. |
23 extension, where a command or function needs to be wrapped, or a |
|
24 command, extension hook, fileset, revset or template needs to be |
|
25 registered. Helper methods are then used as decorators for |
|
26 these various purposes. If an extension spans multiple modules, |
|
27 all helper instances should be merged in the main module. |
24 |
28 |
25 All decorators return the original function and may be chained. |
29 All decorators return the original function and may be chained. |
|
30 |
|
31 Aside from the helper functions with examples below, several |
|
32 registrar method aliases are available for adding commands, |
|
33 configitems, filesets, revsets, and templates. Simply decorate |
|
34 the appropriate methods, and assign the corresponding exthelper |
|
35 variable to a module level variable of the extension. The |
|
36 extension loading mechanism will handle the rest. |
|
37 |
|
38 example:: |
|
39 |
|
40 # ext.py |
|
41 eh = exthelper.exthelper() |
|
42 |
|
43 # As needed: |
|
44 cmdtable = eh.cmdtable |
|
45 configtable = eh.configtable |
|
46 filesetpredicate = eh.filesetpredicate |
|
47 revsetpredicate = eh.revsetpredicate |
|
48 templatekeyword = eh.templatekeyword |
|
49 |
|
50 @eh.command('mynewcommand', |
|
51 [('r', 'rev', [], _('operate on these revisions'))], |
|
52 _('-r REV...'), |
|
53 helpcategory=command.CATEGORY_XXX) |
|
54 def newcommand(ui, repo, *revs, **opts): |
|
55 # implementation goes here |
|
56 |
|
57 eh.configitem('experimental', 'foo', |
|
58 default=False, |
|
59 ) |
|
60 |
|
61 @eh.filesetpredicate('lfs()') |
|
62 def filesetbabar(mctx, x): |
|
63 return mctx.predicate(...) |
|
64 |
|
65 @eh.revsetpredicate('hidden') |
|
66 def revsetbabar(repo, subset, x): |
|
67 args = revset.getargs(x, 0, 0, 'babar accept no argument') |
|
68 return [r for r in subset if 'babar' in repo[r].description()] |
|
69 |
|
70 @eh.templatekeyword('babar') |
|
71 def kwbabar(ctx): |
|
72 return 'babar' |
26 """ |
73 """ |
27 |
74 |
28 def __init__(self): |
75 def __init__(self): |
29 self._uipopulatecallables = [] |
76 self._uipopulatecallables = [] |
30 self._uicallables = [] |
77 self._uicallables = [] |
267 """Decorated function is to be added to the container |
314 """Decorated function is to be added to the container |
268 |
315 |
269 This function takes two arguments, the container and the name of the |
316 This function takes two arguments, the container and the name of the |
270 function to wrap. The wrapping is performed during `uisetup`. |
317 function to wrap. The wrapping is performed during `uisetup`. |
271 |
318 |
272 example:: |
319 Adding attributes to a container like this is discouraged, because the |
273 |
320 container modification is visible even in repositories that do not |
274 @eh.function(context.changectx, 'babar') |
321 have the extension loaded. Therefore, care must be taken that the |
|
322 function doesn't make assumptions that the extension was loaded for the |
|
323 current repository. For `ui` and `repo` instances, a better option is |
|
324 to subclass the instance in `uipopulate` and `reposetup` respectively. |
|
325 |
|
326 https://www.mercurial-scm.org/wiki/WritingExtensions |
|
327 |
|
328 example:: |
|
329 |
|
330 @eh.addattr(context.changectx, 'babar') |
275 def babar(ctx): |
331 def babar(ctx): |
276 return 'babar' in ctx.description |
332 return 'babar' in ctx.description |
277 """ |
333 """ |
278 def dec(func): |
334 def dec(func): |
279 self._duckpunchers.append((container, funcname, func)) |
335 self._duckpunchers.append((container, funcname, func)) |