#!/usr/bin/env python3 # ScintillaData.py - implemented 2013 by Neil Hodgson neilh@scintilla.org # Released to the public domain. # Common code used by Scintilla and SciTE for source file regeneration. # The ScintillaData object exposes information about Scintilla as properties: # Version properties # version # versionDotted # versionCommad # # Date last modified # dateModified # yearModified # mdyModified # dmyModified # myModified # # Information about lexers and properties defined in lexers # lexFiles # sorted list of lexer files # lexerModules # sorted list of module names # lexerProperties # sorted list of lexer properties # propertyDocuments # dictionary of property documentation { name: document string } # sclexFromName # dictionary of SCLEX_* IDs { name: SCLEX_ID } # fileFromSclex # dictionary of file names { SCLEX_ID: file name } # This file can be run to see the data it provides. # Requires Python 3.6 or later import datetime, pathlib, sys, textwrap thisPath = pathlib.Path(__file__).resolve() sys.path.append(str(thisPath.parent.parent.parent / "scintilla" / "scripts")) import FileGenerator neutralEncoding = "cp437" # Each byte value is valid in cp437 def FindModules(lexFile): modules = [] partLine = "" with lexFile.open(encoding=neutralEncoding) as f: lineNum = 0 for l in f.readlines(): lineNum += 1 l = l.rstrip() if partLine or l.startswith("LexerModule"): if ")" in l: l = partLine + l original = l l = l.replace("(", " ") l = l.replace(")", " ") l = l.replace(",", " ") parts = l.split() lexerName = parts[4] if not (lexerName.startswith('"') and lexerName.endswith('"')): print(f"{lexFile}:{lineNum}: Bad LexerModule statement:\n{original}") exit(1) lexerName = lexerName.strip('"') modules.append([parts[1], parts[2], lexerName]) partLine = "" else: partLine = partLine + l return modules def FindLexersInXcode(xCodeProject): lines = FileGenerator.ReadFileAsList(xCodeProject) uidsOfBuild = {} markersPBXBuildFile = ["Begin PBXBuildFile section", "", "End PBXBuildFile section"] for buildLine in lines[FileGenerator.FindSectionInList(lines, markersPBXBuildFile)]: # Occurs for each file in the build. Find the UIDs used for the file. #\t\t[0-9A-F]+ /* [a-zA-Z]+.cxx in sources */ = {isa = PBXBuildFile; fileRef = [0-9A-F]+ /* [a-zA-Z]+ */; }; pieces = buildLine.split() uid1 = pieces[0] filename = pieces[2].split(".")[0] uid2 = pieces[12] uidsOfBuild[filename] = [uid1, uid2] lexers = {} markersLexers = ["/* Lexers */ =", "children", ");"] for lexerLine in lines[FileGenerator.FindSectionInList(lines, markersLexers)]: #\t\t\t\t[0-9A-F]+ /* [a-zA-Z]+.cxx */, uid, _, rest = lexerLine.partition("/* ") uid = uid.strip() lexer, _, _ = rest.partition(".") lexers[lexer] = uidsOfBuild[lexer] return lexers # Properties that start with lexer. or fold. are automatically found but there are some # older properties that don't follow this pattern so must be explicitly listed. knownIrregularProperties = [ "fold", "styling.within.preprocessor", "tab.timmy.whinge.level", "asp.default.language", "html.tags.case.sensitive", "ps.level", "ps.tokenize", "sql.backslash.escapes", "nsis.uservars", "nsis.ignorecase" ] def FindProperties(lexFile): properties = {} with open(lexFile, encoding=neutralEncoding) as f: for l in f.readlines(): if ("GetProperty" in l or "DefineProperty" in l) and "\"" in l: l = l.strip() if not l.startswith("//"): # Drop comments propertyName = l.split("\"")[1] if propertyName.lower() == propertyName: # Only allow lower case property names if propertyName in knownIrregularProperties or \ propertyName.startswith("fold.") or \ propertyName.startswith("lexer."): properties[propertyName] = 1 return properties def FindPropertyDocumentation(lexFile): documents = {} with lexFile.open(encoding=neutralEncoding) as f: name = "" for l in f.readlines(): l = l.strip() if "// property " in l: propertyName = l.split()[2] if propertyName.lower() == propertyName: # Only allow lower case property names name = propertyName documents[name] = "" elif "DefineProperty" in l and "\"" in l: propertyName = l.split("\"")[1] if propertyName.lower() == propertyName: # Only allow lower case property names name = propertyName documents[name] = "" elif name: if l.startswith("//"): if documents[name]: documents[name] += " " documents[name] += l[2:].strip() elif l.startswith("\""): l = l[1:].strip() if l.endswith(";"): l = l[:-1].strip() if l.endswith(")"): l = l[:-1].strip() if l.endswith("\""): l = l[:-1] # Fix escaped double quotes l = l.replace("\\\"", "\"") documents[name] += l else: name = "" for name in list(documents.keys()): if documents[name] == "": del documents[name] return documents def FindCredits(historyFile): credits = [] stage = 0 with historyFile.open(encoding="utf-8") as f: for l in f.readlines(): l = l.strip() if stage == 0 and l == "