def Close(self): """Closes the module. All default sections that have not been overridden will be created. """ if self.GetCollection( vimdoc.FUNCTION) and 'functions' not in self.sections: functions = Block(vimdoc.SECTION) functions.Local(id='functions', name='Functions') self.Merge(functions) if (self.GetCollection(vimdoc.EXCEPTION) and 'exceptions' not in self.sections): exceptions = Block(vimdoc.SECTION) exceptions.Local(id='exceptions', name='Exceptions') self.Merge(exceptions) if self.GetCollection( vimdoc.COMMAND) and 'commands' not in self.sections: commands = Block(vimdoc.SECTION) commands.Local(id='commands', name='Commands') self.Merge(commands) if self.GetCollection( vimdoc.DICTIONARY) and 'dicts' not in self.sections: dicts = Block(vimdoc.SECTION) dicts.Local(id='dicts', name='Dictionaries') self.Merge(dicts) if self.GetCollection(vimdoc.FLAG): # If any maktaba flags were documented, add a default configuration # section to explain how to use them. config = Block(vimdoc.SECTION, is_default=True) config.Local(id='config', name='Configuration') config.AddLine( 'This plugin uses maktaba flags for configuration. Install Glaive' ' (https://github.com/google/glaive) and use the @command(Glaive)' ' command to configure them.') self.Merge(config) if ((self.GetCollection(vimdoc.FLAG) or self.GetCollection(vimdoc.SETTING)) and 'config' not in self.sections): config = Block(vimdoc.SECTION) config.Local(id='config', name='Configuration') self.Merge(config) for backmatter in self.backmatters: if backmatter not in self.sections: raise error.NoSuchSection(backmatter) # Use explicit order as partial ordering and merge with default section # ordering. All custom sections must be ordered explicitly. self.order = self._GetSectionOrder(self.order, self.sections) known = set(self.sections) neglected = sorted(known.difference(self.order)) if neglected: raise error.NeglectedSections(neglected, self.order) # Sections are now in order. for key in self.order: if key in self.sections: # Move to end. self.sections[key] = self.sections.pop(key)
def _AddMaktabaFlagHelp(self): """If any maktaba flags were documented, add a default configuration section to explain how to use them. """ if self.GetCollection(vimdoc.FLAG): block = Block(vimdoc.SECTION, is_default=True) block.Local(id='config', name='Configuration') block.AddLine( 'This plugin uses maktaba flags for configuration. Install Glaive' ' (https://github.com/google/glaive) and use the @command(Glaive)' ' command to configure them.') self.Merge(block)
def Modules(directory): """Creates modules from a plugin directory. Note that there can be many, if a plugin has standalone parts that merit their own helpfiles. Args: directory: The plugin directory. Yields: Module objects as necessary. """ directory = directory.rstrip(os.path.sep) addon_info = None # Check for module metadata in addon-info.json (if it exists). addon_info_path = os.path.join(directory, 'addon-info.json') if os.path.isfile(addon_info_path): try: with open(addon_info_path, 'r') as addon_info_file: addon_info = json.loads(addon_info_file.read()) except (IOError, ValueError) as e: warnings.warn( 'Failed to read file {}. Error was: {}'.format( addon_info_path, e), error.InvalidAddonInfo) plugin_name = None # Use plugin name from addon-info.json if available. Fall back to dir name. addon_info = addon_info or {} plugin_name = addon_info.get('name', os.path.basename(os.path.abspath(directory))) plugin = VimPlugin(plugin_name) # Set module metadata from addon-info.json. if addon_info is not None: # Valid addon-info.json. Apply addon metadata. if 'author' in addon_info: plugin.author = addon_info['author'] if 'description' in addon_info: plugin.tagline = addon_info['description'] # Crawl plugin dir and collect parsed blocks for each file path. paths_and_blocks = [] standalone_paths = [] autoloaddir = os.path.join(directory, 'autoload') for (root, dirs, files) in os.walk(directory): # Visit files in a stable order, since the ordering of e.g. the Maktaba # flags below depends upon the order that we visit the files. dirs.sort() files.sort() # Prune non-standard top-level dirs like 'test'. if root == directory: dirs[:] = [x for x in dirs if x in DOC_SUBDIRS + ['after']] if root == os.path.join(directory, 'after'): dirs[:] = [x for x in dirs if x in DOC_SUBDIRS] for f in files: filename = os.path.join(root, f) if os.path.splitext(filename)[1] == '.vim': relative_path = os.path.relpath(filename, directory) with open(filename) as filehandle: lines = list(filehandle) blocks = list(parser.ParseBlocks(lines, filename)) # Define implicit maktaba flags for files that call # maktaba#plugin#Enter. These flags have to be special-cased here # because there aren't necessarily associated doc comment blocks and # the name is computed from the file name. if (not relative_path.startswith('autoload' + os.path.sep) and relative_path != os.path.join( 'instant', 'flags.vim')): if ContainsMaktabaPluginEnterCall(lines): flagpath = relative_path if flagpath.startswith('after' + os.path.sep): flagpath = os.path.relpath(flagpath, 'after') flagblock = Block(vimdoc.FLAG, is_default=True) name_parts = os.path.splitext(flagpath)[0].split( os.path.sep) flagname = name_parts.pop(0) flagname += ''.join('[' + p + ']' for p in name_parts) flagblock.Local(name=flagname) flagblock.AddLine( 'Configures whether {} should be loaded.'. format(relative_path)) default = 0 if flagname == 'plugin[mappings]' else 1 # Use unbulleted list to make sure it's on its own line. Use # backtick to avoid helpfile syntax highlighting. flagblock.AddLine( ' - Default: {} `'.format(default)) blocks.append(flagblock) paths_and_blocks.append((relative_path, blocks)) if filename.startswith(autoloaddir): if blocks and blocks[0].globals.get('standalone'): standalone_paths.append(relative_path) docdir = os.path.join(directory, 'doc') if not os.path.isdir(docdir): os.mkdir(docdir) modules = [] main_module = Module(plugin_name, plugin) for (path, blocks) in paths_and_blocks: # Skip standalone paths. if GetMatchingStandalonePath(path, standalone_paths) is not None: continue namespace = None if path.startswith('autoload' + os.path.sep): namespace = GetAutoloadNamespace(os.path.relpath(path, 'autoload')) for block in blocks: main_module.Merge(block, namespace=namespace) modules.append(main_module) # Process standalone modules. standalone_modules = {} for (path, blocks) in paths_and_blocks: standalone_path = GetMatchingStandalonePath(path, standalone_paths) # Skip all but standalone paths. if standalone_path is None: continue assert path.startswith('autoload' + os.path.sep) namespace = GetAutoloadNamespace(os.path.relpath(path, 'autoload')) standalone_module = standalone_modules.get(standalone_path) # Initialize module if this is the first file processed from it. if standalone_module is None: standalone_module = Module(namespace.rstrip('#'), plugin) standalone_modules[standalone_path] = standalone_module modules.append(standalone_module) for block in blocks: standalone_module.Merge(block, namespace=namespace) for module in modules: module.Close() yield module