File indexing completed on 2025-01-05 04:26:51

0001 # Copyright 2013  Anmol Ahuja <darthcodus@gmail.com>
0002 #
0003 # This program is free software; you can redistribute it and/or
0004 # modify it under the terms of the GNU General Public License as
0005 # published by the Free Software Foundation; either version 2 of
0006 # the License, or (at your option) any later version.
0007 #
0008 # This program is distributed in the hope that it will be useful,
0009 # but WITHOUT ANY WARRANTY; without even the implied warranty of
0010 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0011 # GNU General Public License for more details.
0012 #
0013 # You should have received a copy of the GNU General Public License
0014 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
0015 
0016 # TODOs:
0017 # NO enums like in AmarokInfoScript.cpp handled, global func not handled
0018 # handle enums in scriptdox
0019 # Handle multiple classes in a file
0020 # Handle docs in script dox
0021 
0022 import os
0023 import sys
0024 import re
0025 
0026 prototype = {}
0027 scriptMap = {}
0028 autoComplete = []
0029 
0030 def addElement( scriptMap, name, classDoc = '' ):
0031     #if not scriptMap.has_key( name ):
0032     scriptMap[name] = ["\nclass " + name + "{\n"]
0033 
0034 def generatePseudoHeader( rootDir, fileName ):
0035     global prototype
0036     global scriptMap
0037     global autoComplete
0038 
0039     headerPath = os.path.join(rootDir, fileName+".h")
0040 
0041     className = None
0042     with open( headerPath, 'r' ) as f:
0043         contents = f.read()
0044         match = re.search( r'//[\s]*SCRIPTDOX[\s:]*(.*)', contents )
0045         if match is None:
0046             return
0047         s = [item for item in match.group(1).split(' ') if item]
0048         if 'PROTOTYPE' in s:
0049             className = s[2].strip()
0050             prototype[ s[1] ] = className
0051         else:
0052             className = s[0].strip()
0053             autoComplete.append( className )
0054         addElement( scriptMap, className )#, classDoc )
0055         classBeg = contents.index(match.group(0))
0056         if True:
0057             properties = re.findall( r"(Q_PROPERTY\(\s*[\w:<>]*\s*([\w:<>\*]*).*\))", contents, re.MULTILINE )
0058             for qProperty in properties:
0059                 if 'PROTOTYPE' not in s:
0060                     autoComplete.append( className + "." + qProperty[1] )
0061                 scriptMap[className].append( qProperty[0] )
0062             #re.findall( r"public slots:[\s\n]*(.*)[\n\s]*(protected|private|public|slots|};|signals):" #huh, works without |signals?!
0063             #            , contents, re.MULTILINE|re.DOTALL )
0064             accessMap = {}
0065             for access in ( 'private slots:', 'protected slots:', 'public slots:', 'private:', 'public:', 'protected:', 'signals:', '};' ):
0066                 indexFromBeg = contents[classBeg:].find( access ) + classBeg
0067                 if indexFromBeg != -1:
0068                     accessMap[ indexFromBeg ] = access
0069 
0070             sortedKeys = sorted( accessMap.keys() )
0071             for access in ('public slots:', 'signals:'):
0072                 if( access in contents ):
0073                     accessIndex = contents[classBeg:].find( access ) + classBeg
0074                     selections = contents[ accessIndex : sortedKeys[sortedKeys.index(accessIndex)] ]
0075                     functions = filter( None, re.findall( r'(.*;)', selections ) )
0076                     if 'PROTOTYPE' not in s:
0077                         for function in functions:
0078                              reg = re.search( r'.*[\s\n](.*)[\s\n]*\(', function.strip())
0079                              if reg:
0080                                 funcName = reg.group(1).replace('*','').replace('&','')
0081                                 autoComplete.append( className+"."+ funcName + '(' )
0082                     scriptMap[className].append( selections )
0083 
0084 def traverseDir( dirPath, opDir ):
0085     for root, subFolder, files in os.walk(dirPath):
0086         for fileName in files:
0087             if fileName.endswith( ".cpp" ):
0088                 generatePseudoHeader( root, fileName[:-4] )
0089     #substitute prototypes
0090     for scriptClass in scriptMap:
0091         for line in scriptMap[scriptClass]:
0092             re.sub( r"\b("+'|'.join(prototype.keys())+r')\b', lambda word: prototype[word.group()], line )
0093 
0094     f = open( os.path.join( opDir, "PseudoHeader.h" ), 'w' )
0095     for scriptClass in scriptMap:
0096         f.write( '\n'.join(scriptMap[scriptClass]) + '};\n' )
0097     f.close()
0098 
0099     autoComplete.sort()
0100     f = open( os.path.join( opDir, "AutoComplete.txt" ), 'w' )
0101     f.write( '\n'.join(autoComplete) )
0102     f.close()
0103 
0104 def main():
0105     scriptPath = sys.argv[1]
0106     if not os.path.exists(sys.argv[2]):
0107         os.makedirs(sys.argv[2])
0108     traverseDir( sys.argv[1], sys.argv[2] )
0109 
0110 if __name__ == "__main__":
0111     main()