python-fu-dump / dump.py

bworkman 0ae30c4 
bworkman df07850 
bworkman c3aeaea 

bworkman 0ae30c4 


bworkman 735f874 

bworkman c3aeaea 
bworkman 735f874 
bworkman b9043eb 
bworkman df07850 
bworkman b9043eb 
bworkman df07850 

bworkman b9043eb 
bworkman df07850 
bworkman b9043eb 
bworkman df07850 


bworkman b9043eb 
bworkman df07850 

bworkman b9043eb 
bworkman 03633bd 


bworkman b9043eb 
bworkman e1d1609 







bworkman b9043eb 
bworkman e1d1609 

bworkman 3499b3d 




bworkman b9043eb 
bworkman 3499b3d 
bworkman e1d1609 




bworkman e1e44fc 

bworkman 03633bd 

bworkman a6696cd 
bworkman 6c90636 










bworkman 3fd2ffb 





bworkman e1e44fc 
bworkman 3fd2ffb 
bworkman 6c90636 
bworkman b9fe67a 
bworkman b9043eb 
bworkman 6c90636 












bworkman b9043eb 




bworkman 6c90636 
bworkman 0ae30c4 

bworkman 6c90636 












bworkman 0ae30c4 

























bworkman 6c90636 
bworkman 0ae30c4 
bworkman b9043eb 
bworkman 6c90636 













bworkman 673b870 
bworkman b9043eb 


bworkman 3fd2ffb 
bworkman bcddcdb 
bworkman b9043eb 
bworkman 6c90636 
bworkman df07850 
bworkman b9043eb 
bworkman 6c90636 











bworkman 673b870 
bworkman b9043eb 


bworkman 3fd2ffb 
bworkman e1e44fc 
bworkman b9043eb 
bworkman 6c90636 
bworkman e1e44fc 
bworkman b9043eb 
bworkman 6c90636 












bworkman 673b870 
bworkman b9043eb 


bworkman eddf607 
bworkman b9043eb 


bworkman eddf607 
bworkman e1e44fc 

bworkman b9043eb 
bworkman e1e44fc 
bworkman b9043eb 
bworkman e1e44fc 
bworkman b9043eb 
bworkman 874cbe1 

bworkman e1e44fc 
bworkman b9043eb 
bworkman e1e44fc 

bworkman eddf607 
bworkman 6c90636 
bworkman e1e44fc 
bworkman b9043eb 
bworkman 6c90636 











bworkman 673b870 
bworkman b9043eb 

bworkman e1d1609 
bworkman b9043eb 



bworkman 673b870 
bworkman b9043eb 


bworkman e1d1609 

bworkman b9043eb 
bworkman e1d1609 

bworkman 6c90636 
bworkman e1d1609 
bworkman c3aeaea 
bworkman 6c90636 











bworkman c3aeaea 





bworkman e1d1609 
bworkman c3aeaea 



bworkman e1d1609 
bworkman c3aeaea 
bworkman 6c90636 
bworkman e1d1609 
bworkman c3aeaea 
bworkman 6c90636 










bworkman c3aeaea 


bworkman e1d1609 
bworkman c3aeaea 




bworkman e1d1609 
bworkman c3aeaea 
bworkman 6c90636 
bworkman e1d1609 
bworkman c3aeaea 
bworkman 6c90636 














bworkman c3aeaea 


bworkman e1d1609 
bworkman c3aeaea 
bworkman e1d1609 
bworkman c3aeaea 
bworkman e1d1609 
bworkman c3aeaea 

bworkman e1d1609 
bworkman c3aeaea 





bworkman e1d1609 
bworkman c3aeaea 
bworkman 3499b3d 
bworkman c3aeaea 



bworkman e1d1609 
bworkman c3aeaea 
bworkman e1d1609 
bworkman c3aeaea 
bworkman 6c90636 
bworkman c3aeaea 
bworkman b9043eb 
bworkman 6c90636 










bworkman b9043eb 
bworkman 673b870 


bworkman b9043eb 
bworkman 673b870 




bworkman b9043eb 
bworkman 673b870 



bworkman 6c90636 
bworkman 673b870 
bworkman b9043eb 
bworkman 6c90636 












bworkman c3aeaea 

bworkman b9043eb 

bworkman c3aeaea 




bworkman b9043eb 
bworkman 6c90636 
bworkman b9043eb 


bworkman 6c90636 










bworkman b9043eb 

bworkman 874cbe1 

bworkman b9043eb 
bworkman 874cbe1 




bworkman b9043eb 
bworkman 874cbe1 

bworkman b9043eb 

bworkman 6c90636 
bworkman b9043eb 
bworkman 874cbe1 
bworkman 6c90636 










bworkman 874cbe1 






















bworkman 6c90636 
bworkman b9043eb 
bworkman 874cbe1 
bworkman 6c90636 











bworkman 874cbe1 


bworkman 6c90636 
bworkman c3aeaea 
bworkman 673b870 
bworkman 6c90636 















bworkman bcddcdb 

bworkman 0ae30c4 

bworkman b9043eb 
bworkman b9fe67a 
bworkman b9043eb 
bworkman 3fd2ffb 
bworkman b9043eb 


bworkman 673b870 
bworkman b9043eb 















bworkman eddf607 
bworkman 673b870 
bworkman b9043eb 
bworkman 673b870 

bworkman b9043eb 
bworkman 673b870 
bworkman b9043eb 

bworkman 673b870 
bworkman 874cbe1 





bworkman b9043eb 
bworkman 673b870 
bworkman b9043eb 




bworkman 874cbe1 
bworkman b9043eb 


bworkman 874cbe1 
bworkman b9043eb 
bworkman 874cbe1 
bworkman eddf607 
bworkman 874cbe1 
bworkman b9043eb 
bworkman 874cbe1 
bworkman eddf607 
bworkman 874cbe1 


bworkman eddf607 
bworkman 874cbe1 
bworkman eddf607 
bworkman 874cbe1 





bworkman eddf607 
bworkman 874cbe1 



bworkman b9043eb 
bworkman 874cbe1 


bworkman b9043eb 


bworkman 874cbe1 
bworkman b8c83c7 
bworkman 673b870 
bworkman b9043eb 
bworkman e1d1609 
bworkman b9043eb 

bworkman 0ae30c4 
bworkman 6c90636 
bworkman 0ae30c4 
bworkman 6c90636 














bworkman 0ae30c4 

















bworkman 673b870 
bworkman b9043eb 
bworkman 673b870 

bworkman 0ae30c4 





bworkman 874cbe1 
bworkman 6c90636 
  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
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
from gimpfu import *
from string import Template
from datetime import datetime
from collections import *
import gtk
import os
import ctypes
import unicodedata
import re
from pprint import pprint, pformat

__CSS = "html,body{ width:100%; height:100%; margin:0px}body{ width:578px; max-width:578px; margin:24px auto 0px 36px}p,table{ margin:0px 0px 0px 12px}nav{ display:block; margin-bottom:6px; text-align:center}nav.main a{ font-size:1.05em}h1{ margin-top:0px}h1,h4{ margin-bottom:0px}div#author{ text-align:right; font-style:italic}span.date{ font:bold 14px Monospace,small-caps}table{ font-family:'Trebuchet MS',Arial,Helvetica,sans-serif; width:100%; border-collapse:collapse}table td,table th { font-size:1em; border:1px solid SlateGray; padding:3px 7px 2px 7px}table th{ font-size:1.1em; text-align:left; padding-top:5px; padding-bottom:4px; background-color:LightSlateGray; color:#fff}table tr.alt td { color:#000; background-color:#C9CFD6}"

__PROC_HTML = """<!DOCTYPE html>
<html>
        <head>
                <title>pdb: ${name}</title>

                <meta name="description" content="${blurb}">
                <meta name="author" content="Code Fox">
                <meta charset="UTF-8">

                <link rel="stylesheet" type="text/css" href="../main.css">
        </head>
        <body>
                ${body}
        </body>
</html>
"""
__INDEX_HTML = """<!DOCTYPE html>
<html>
        <head>
                <title>pdb: index</title>

                <meta name="description" content="">
                <meta name="author" content="Code Fox">
                <meta charset="UTF-8">

                ${css}
        </head>
        <body>
                <a id="top"></a>
                <div style="text-align:center">
                        <div style="display:inline-block; margin:0px auto 0px auto;">
                                <h1>Gimp Plugin Database</h1>
                                <div id="author">
                                        <span class="date">${date}</span>
                                </div>
                        </div>
                </div>
                ${body}
        </body>
</html>
"""

MessageBox = ctypes.windll.user32.MessageBoxA

def escape_html(html):
        """****f* dump/escape_html
        *       DESCRIPTION
        *               escapes problem characters in unicode strings and returns an ascii encoded representation
        *       ARGUMENTS
        *               html -- unicode string to escape
        *       SIDE EFFECTS
        *               None.
        *       RESULT
        *               ascii encoded escaped string
        *       SOURCE
        *"""
        html = unicode(html)
        html = html.replace('&', '&amp;')
        html = html.replace('<', '&lt;')
        html = html.replace('>', '&gt;')
        html = html.replace('"', '&quot;')
        html = html.replace("'", '&#39;')

        return html.encode('ascii', 'ignore')
"""*******"""

def slugify(procedureName):
        """****f* dump/slugify
        *       DESCRIPTION
        *               Normalizes string, converts to lowercase, removes non-alpha characters, and converts spaces to hyphens.
        *       ARGUMENTS
        *               procedureName -- string to normalize
        *       SIDE EFFECTS
        *               None.
        *       NOTE
        *               Based on code in: Django
        *       RESULT
        *               normalized string
        *       SOURCE
        *"""
        procedureName = unicodedata.normalize('NFKD', unicode(procedureName))
        procedureName = procedureName.encode('ascii', 'ignore')
        procedureName = re.sub('[^\w\s-]', '', procedureName).strip().lower()
        procedureName = re.sub('[-\s]+', '-', procedureName)
        return procedureName
"""*******"""

def get_dir() :
        """****f* dump/get_dir
        *       DESCRIPTION
        *               prompts the user with a directory selection dialog
        *       ARGUMENTS
        *               None.
        *       SIDE EFFECTS
        *               None.
        *       NOTE
        *               requires PyGtk 2.3.90 or later
        *       RESULT
        *               path of the directory selected
        *       SOURCE
        *"""
        response = ""

        # Check for new pygtk: this is new class in PyGtk 2.4
        if (gtk.pygtk_version < (2,3,90)) :
                MessageBox(None, "This plugin requires PyGtk 2.3.90 or later", "Error", 0)
                return response

        dialog = gtk.FileChooserDialog(
                "Dump to...",
                None,
                gtk.FILE_CHOOSER_ACTION_OPEN,
                (
                        gtk.STOCK_CANCEL,
                        gtk.RESPONSE_CANCEL,
                        gtk.STOCK_OPEN,
                        gtk.RESPONSE_OK
                )
        )
        dialog.set_default_response(gtk.RESPONSE_OK)
        dialog.set_action(gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER)

        if (dialog.run() == gtk.RESPONSE_OK) :
                response = dialog.get_filename()
        dialog.destroy()

        return response
"""*******"""

def variable_type(t) :
        """****f* dump/variable_type
        *       DESCRIPTION
        *               returns a string representation of a python-fu variable type
        *       ARGUMENTS
        *               t -- python-fu type to check
        *       SIDE EFFECTS
        *               None.
        *       NOTE
        *               type "PF_REGION" is in the python-fu documentation, but not defined at run-time
        *       RESULT
        *               "unknown" -- if the type could not be found
        *               string representation otherwise
        *       SOURCE
        *"""

        types = {PF_INT8:"PF_INT8",PF_INT16:"PF_INT16",PF_INT32:"PF_INT32",PF_INT:"PF_INT",PF_FLOAT:"PF_FLOAT",PF_STRING:"PF_STRING",PF_VALUE:"PF_VALUE",PF_COLOR:"PF_COLOR",PF_COLOUR:"PF_COLOUR",PF_IMAGE:"PF_IMAGE",PF_LAYER:"PF_LAYER",PF_CHANNEL:"PF_CHANNEL",PF_DRAWABLE:"PF_DRAWABLE",PF_TOGGLE:"PF_TOGGLE",PF_BOOL:"PF_BOOL",PF_RADIO:"PF_RADIO",PF_SLIDER:"PF_SLIDER",PF_SPINNER:"PF_SPINNER",PF_ADJUSTMENT:"PF_ADJUSTMENT",PF_FONT:"PF_FONT",PF_FILE:"PF_FILE",PF_BRUSH:"PF_BRUSH",PF_PATTERN:"PF_PATTERN",PF_GRADIENT:"PF_GRADIENT",PF_PALETTE:"PF_PALETTE"}

        if (t not in types) :
                return "unknown"

        return types[t]
"""*******"""

def procedure_type(t) :
        """****f* dump/procedure_type
        *       DESCRIPTION
        *               returns a string representation of a python-fu procedure type
        *       ARGUMENTS
        *               t -- python-fu type to check
        *       SIDE EFFECTS
        *               None.
        *       RESULT
        *               "unknown" -- if the type could not be found
        *               string representation otherwise
        *       SOURCE
        *"""

        types = {PLUGIN:"PROC_PLUG_IN",EXTENSION:"PROC_EXTENSION",TEMPORARY:"PROC_TEMPORARY"}

        if (t not in types) :
                return "unknown"

        return types[t]
"""*******"""

def alt_table(variables) :
        """****f* dump/alt_table
        *       DESCRIPTION
        *               returns an HTML table containing the list of variables in a string
        *       ARGUMENTS
        *               variables -- list of python-fu variables to format
        *       SIDE EFFECTS
        *               None.
        *       NOTE
        *               table contains alternating colored rows
        *       RESULT
        *               string containing HTML table
        *       SOURCE
        *"""

        if(0 == len(variables)):
                return "<p>None</p>"

        table = '<table>\n${offset}\t<thead>\n${offset}\t\t<tr>\n${offset}\t\t\t<th>Type</th>\n${offset}\t\t\t<th>Name</th>\n${offset}\t\t\t<th>Description</th>\n${offset}\t\t</tr>\n${offset}\t</thead>\n${offset}\t<tbody>${body}\n${offset}</tbody>\n${offset}</table>'

        tr = '\n${offset}<tr ${class}>\n${offset}\t<td>${type}</td>\n${offset}\t<td>${name}</td>\n${offset}\t<td>${desc}</td>\n${offset}</tr>'

        row = {"offset":"\t\t\t"}
        html = ""
        alt = False
        for item in variables :
                row["class"] = ""
                if (alt is True) :
                        row["class"] = ' class="alt"'
                row["type"] = variable_type(item[0])
                row["name"] = escape_html(item[1])
                row["desc"] = escape_html(item[2])

                html += Template(tr).safe_substitute(row)
                alt = not alt

        return Template(table).safe_substitute({"body":html, "offset":"\t\t"})
"""*******"""

def index_table(links, maxRowLen=5):
        """****f* dump/index_table
        *       DESCRIPTION
        *               returns an html table containing the list of links in a string
        *       ARGUMENTS
        *               links           -- list of link objects (dictionary containing keys [href, name])
        *               maxRowLen       -- maximum number of links to display per a table row
        *       SIDE EFFECTS
        *               None.
        *       RESULT
        *               string containing HTML table
        *       SOURCE
        *"""

        if(0 == len(links)):
                return ""

        buf = '\t\t<table>\n\t\t\t<tr>\n'
        count = 0
        for link in links:
                count += 1

                buf += Template('\t\t\t\t<td><a href="${href}" title="${name}">${name}</a></td>\n').safe_substitute(link)

                if 0 == (count % maxRowLen):
                        buf += '\t\t\t</tr>\n\t\t\t<tr>\n'

        buf += '\t\t\t</tr>\n\t\t</table>'

        return buf
"""*******"""

def insert(root, path):
        """****f* dump/insert
        *       DESCRIPTION
        *               inserts a path into a tree 
        *       ARGUMENTS
        *               root    -- root node (touple:string,list) to use when inserting
        *               path    -- list of strings to insert
        *       SIDE EFFECTS
        *               inserts path into tree starting at root
        *       RESULT
        *               None.
        *       SOURCE
        *"""
        for part in path:
                ptr = None
                for tup in root[1]:
                        if (tup[0] == part):
                                ptr = tup
                                break

                if None == ptr:
                        ptr = (part, list())
                        root[1].append(ptr)
                        root[1].sort(key=lambda tup: tup[0])

                root = ptr
"""*******"""

def size(root):
        """****f* dump/size
        *       DESCRIPTION
        *               returns the number of nodes in a tree
        *       ARGUMENTS
        *               root    -- root node (touple:string,list) to start counting from
        *       SIDE EFFECTS
        *               None.
        *       RESULT
        *               the number of nodes in the tree
        *       SOURCE
        *"""
        children = 0
        unvisited = deque()
        unvisited.append(root)

        while 0 != len(unvisited):
                node = unvisited.popleft()
                children += 1
                for tup in node[1]:
                        unvisited.append(tup)

        return children
"""*******"""

def namespaces(root, delimiter="-", minSize=10):
        """****f* dump/namespaces
        *       DESCRIPTION
        *               returns the list of namespaces from the given tree
        *       ARGUMENTS
        *               root            -- root node (touple:string,list) to generate namespaces from
        *               delimiter       -- the delimiter to join the namespace elements with
        *               minSize         -- the minimum number of items that must reside in the namespace before returning it
        *       SIDE EFFECTS
        *               None.
        *       NOTE
        *               if a direct child of root node doesnt contain minSize children, it is returned anyway
        *       RESULT
        *               list of namespaces (strings joined on delimiter) contained in root
        *       SOURCE
        *"""
        ns_list = list()
        unvisited = list()
        visited = dict()

        unvisited.append(root)

        while 0 != len(unvisited):

                node = unvisited[-1]
                namespace = delimiter.join(map(lambda tup: tup[0], unvisited))

                for child in node[1]:
                        childspace = namespace + delimiter + child[0]
                        if(childspace not in visited):
                                visited[childspace] = True
                                unvisited.append(child)
                                break

                if(node == unvisited[-1]):
                        # post fix; no new unvisited children found
                        if(size(node) > minSize):
                                ns_list.append(namespace)
                        elif (node == root):
                                ns_list.append(namespace)

                        unvisited.pop()

        return ns_list
"""*******"""

def make_heading_filter(procedureNames):
        """****f* dump/make_heading_filter
        *       DESCRIPTION
        *               closure for headings filter
        *       ARGUMENTS
        *               procedureNames -- list of procedure names to filter headings for
        *       SIDE EFFECTS
        *               None.
        *       RESULT
        *               filter function for headings
        *       SOURCE
        *"""
        procedureNames = list(procedureNames)

        def filter_headings(ns):

                lst = filter(lambda name: name.startswith(ns),procedureNames)

                if( 0 == len(lst)):
                        return None

                for tmp in lst:
                        procedureNames.remove(tmp)

                return True

        return filter_headings
"""*******"""

def headings(procedureNames, delimiter="-", minSize=7):
        """****f* dump/headings
        *       DESCRIPTION
        *               return a list of headings for procedure name index
        *       ARGUMENTS
        *               procedureNames  -- list of procedure names to generate headings for
        *               delimiter       -- character that separates spaces in procedureNames
        *               minSize         -- minimum number of procedures that should be under a namespace before making it a heading
        *       SIDE EFFECTS
        *               None.
        *       RESULT
        *               list of headings to use in index
        *       SOURCE
        *"""
        root = ("root", list())

        for pname in procedureNames:
                insert(root, pname.split(delimiter))

        heading_list = list()
        for node in root[1]:
                heading_list.extend(namespaces(node, delimiter, minSize))

        return filter(make_heading_filter(procedureNames),heading_list)
"""*******"""


def transform(procedure) :
        """****f* dump/transform
        *       DESCRIPTION
        *               maps a python-fu procedure object to dictionary
        *       ARGUMENTS
        *               procedure -- the python-fu procedure object to transform
        *       SIDE EFFECTS
        *               None.
        *       RESULT
        *               dictionary containing mapped attributes
        *       SOURCE
        *"""
        dct = dict()

        dct["name"] = escape_html(procedure.proc_name)
        dct["authors"] = "<br>".join(map(lambda author: escape_html(author.strip()),procedure.proc_author.split(',')))

        dct["date"] = escape_html(procedure.proc_date)
        dct["copyright"] = escape_html(procedure.proc_copyright)
        dct["blurb"] = escape_html(procedure.proc_blurb)
        dct["help"] = escape_html(procedure.proc_help)
        dct["type"] = procedure_type(escape_html(procedure.proc_type))

        dct["parameters"] = alt_table(procedure.params)
        dct["results"] = alt_table(procedure.return_vals)

        return dct
"""*******"""

def procedure_body(procedure):
        """****f* dump/procedure_body
        *       DESCRIPTION
        *               returns an HTML representation of a python-fu procedure object in a string
        *       ARGUMENTS
        *               procedure -- the python-fu procedure object to format
        *       SIDE EFFECTS
        *               None.
        *       RESULT
        *               HTML string containing procedure attributes
        *       SOURCE
        *"""
        return Template("""
                <hr style="margin-bottom:0px;"/>
                <div style="display:inline-block;">
                        <h1>${name}</h1>
                        <div id="author">${authors}</div>
                </div>
                <hr style="margin-bottom:0px;"/>
                <p id="copyright" style="margin:0">
                        <span class="date">${date}</span><br>
                        ${copyright}
                </p>
                <h4>Description</h4>
                <p id="description">${blurb}</p>
                <h4>Help</h4>
                <p id="help">${help}</p>
                <hr />
                <h4>Type</h4>
                <p id="type">${type}</p>
                <h4>Parameters</h4>
                ${parameters}
                <h4>Return</h4>
                ${results}
                <hr style="margin-bottom:0px;" />""").safe_substitute(transform(procedure))
"""*******"""

def make_linker(base="",ext=".html") :
        """****f* dump/make_linker
        *       DESCRIPTION
        *               closure for procedure name to HTML anchor
        *       ARGUMENTS
        *               base    -- a base for the anchor href
        *               ext     -- tail for the anchor href
        *       SIDE EFFECTS
        *               None.
        *       RESULT
        *               function to construct anchors
        *       SOURCE
        *"""
        def linker(pname):
                return {"name":pname,"href":"%s%s%s"%(base, slugify(pname), ext)}
        return linker
"""*******"""

def dump_pdb(minSize, singleFile) :
        """****f* dump/dump_pdb
        *       DESCRIPTION
        *               python-fu function, outputs procedural database to HTML
        *       ARGUMENTS
        *               minSize         -- minimum number of children in a namespace before giving it a separate index table
        *               singleFile      -- boolean value, if true output entire procedural database and index into one file
        *       SIDE EFFECTS
        *               writes HTML files containing procedural database to directory chosen user
        *               if single file -- writes "index.html" out to chosen directory
        *               else -- writes "index.html", "main.css" out to chosen directory, and one html file per function to <directory>/pdb/
        *       NOTE
        *               headings are determined dynamically at run-time by breaking the procedural database into namespaces and taking those namespaces which have a minimum number of elements
        *               headings are mapped alphabetically, depth-first, to ensure proper output
        *       RESULT
        *               None.
        *****"""
        root = get_dir()
        if("" == root) :
                return None

        now = datetime.now().strftime("%A, %d. %B %Y %I:%M%p")

        css = Template('<style type="text/css">\n\t\t\t${css}\n\t\t</style>\n').safe_substitute({"css":__CSS})

        if(singleFile is not True):
                # create sub directory if it doesnt exist
                tmp = os.path.join(root,"pdb")

                if not os.path.exists(tmp):
                        os.makedirs(tmp)

                with open(os.path.join(root, "main.css"),'w') as f:
                        f.write(__CSS)

                css = '<link rel="stylesheet" type="text/css" href="main.css">'

        # get all procedure names from PDB
        procedure_names = gimp.pdb.query()
        procedure_names.sort()

        # get comprehensive list of namespaces
        heading_list = headings(procedure_names, '-', minSize)

        # for every namespace, create a top index link
        index_buf = '<hr>\n\t\t<nav class="main">\n\t\t\t'
        for heading in heading_list :
                index_buf += Template('<a href="#${heading}">${heading}</a>').safe_substitute({"heading":heading})

                if(heading != heading_list[-1]):
                        index_buf += " &bull; "

        index_buf += "\n\t\t</nav>\n\t\t<hr>\n"
        proc_buf = ""

        if singleFile is True:
                linker = make_linker("#","")
        else:
                linker = make_linker("pdb/")
                proc_linker = make_linker()

        # for every namespace, create a heading, anchor and index table
        for heading in heading_list :

                index_buf += Template('\t\t<a id="${heading}"><h4>${heading}</h4></a>\n').safe_substitute({"heading":heading})

                space = filter(lambda pname: pname.startswith(heading),procedure_names)

                index_buf += index_table(map(linker,space))
                index_buf += '\n\t\t<nav><a href="#top">top</a></nav>\n'

                # buffer procedure output for this namespace
                for i in range(len(space)):

                        if (singleFile is True):
                                proc_buf += Template('\t\t<a id="${anchor}"></a>').safe_substitute({"anchor":space[i]})
                                proc_buf += procedure_body(pdb[space[i]])

                                tmp = linker(heading)
                                tmp["offset"] = "\t\t"
                                proc_buf += Template('${offset}<nav>\n${offset}\t<a href="#top" style="display:inline-block; margin-right:40px;">top</a><a href="${href}">namespace</a>\n${offset}</nav>\n').safe_substitute(tmp)

                        else:
                                tmp = "\n\t\t<nav>\n\t\t\t"
                                if(i > 0):
                                        tmp += Template('<a href="${href}" style="float:left;">previous</a>').safe_substitute(proc_linker(space[i-1]))

                                tmp += '<a href="../index.html">index</a>'

                                if(i < (len(space) - 1)):
                                        tmp += Template('<a href="${href}" style="float:right;">next</a>').safe_substitute(proc_linker(space[i+1]))

                                tmp += "\n\t\t</nav>\n"

                                proc_buf = tmp + procedure_body(pdb[space[i]]) + tmp

                                with open(os.path.join(root,"pdb","%s.html"%slugify(space[i])), "w+") as f :
                                        f.write(Template(__PROC_HTML).safe_substitute({"body":proc_buf}))

                                proc_buf = ""

                # end procedure buffering

                # mark all procedures in this namespace as done
                procedure_names = filter(lambda pname: pname not in space, procedure_names)
        # end index buffering

        # write index, if not singleFile, proc_buff will be empty!
        with open(os.path.join(root,"index.html"), "w+") as f :
                f.write(Template(__INDEX_HTML).safe_substitute({"date":now,"body":index_buf + proc_buf, "css":css}))

        return None
"""*******"""

"""****h* dump/dump
*       DESCRIPTION
*               Python-fu plug-in that outputs the gimp procedural database in formatted HTML and CSS
*       ARGUMENTS
*               None.
*       SIDE EFFECTS
*               Adds to GIMP menu "Help", item "Procedure Dump"
*       RESULT
*               None.
*       NOTE
*               provides two configurable options:
*               single file - output is dumped into one file "index.html" in selected directory
*               scale - the minimum number of sub items a namespace must contain to be broken up into its own index (very large number => very few index tables)
*       SOURCE
*"""
register(
        #name
        "dump-pdb",
        #blurb
        "dumps pdb database to HTML",
        #help
        "man up buttercup",
        #author
        "codefox",
        #copyright
        "MIT license => rtfm",
        #date
        "Jan 29, 2013",
        #menu path
        "<Toolbox>/Help/Procedure Dump",
        #image types
        None,
        #params
        [
                (PF_INT, "scale", "scale", 7),
                (PF_BOOL, "single-file", "single-file", False)
        ],
        #results
        [],
        #function
        dump_pdb
)

main()
"""*******"""
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.