Commits

Johannes Köster  committed c39548e

Provide a customized bash completion that also proposes rule names and file names.

  • Participants
  • Parent commits 2cab4e7

Comments (0)

Files changed (4)

 # coding: utf-8
-from setuptools import setup, Command
+from setuptools import setup
 import sys
 
 if sys.version_info < (3,2):
 from snakemake import __version__, get_argument_parser
 
 
-class Completion(Command):
-    description = "create a shell completion files using genzshcomp"
-    user_options = []
-    
-    def initialize_options(self):
-        pass
-
-    def finalize_options(self):
-        pass
-
-    def run(self):
-        from genzshcomp import CompletionGenerator
-        parser = get_argument_parser()
-        for fmt in "bash zsh".split():
-            generator = CompletionGenerator(parser=parser, output_format=fmt)
-            with open("snakemake/completion.{}.txt".format(fmt), "w") as out:
-                print(generator.get(), file=out)
-        
-    
 setup(
     name='snakemake',
     version=__version__,
     url='http://snakemake.googlecode.com',
     packages=['snakemake'],
     entry_points={
-        "console_scripts": ["snakemake = snakemake:main"]
+        "console_scripts": ["snakemake = snakemake:main", "snakemake-bash-completion = snakemake:bash_completion"]
     },
-    cmdclass={"completion": Completion},
     package_data={'': ['*.css', '*.sh']},
     classifiers=[
         "Development Status :: 5 - Production/Stable",

File snakemake/__init__.py

 # -*- coding: utf-8 -*-
 
 import os
+import glob
 import argparse
 from argparse import ArgumentError
 import logging
     parser.add_argument(
         "--debug", action="store_true", help="Print debugging output.")
     parser.add_argument(
+        "--bash-completion", action="store_true", help="Register bash completion for snakemake.")
+    parser.add_argument(
         "--version", "-v", action="version", version=__version__)
     return parser
 
 
+def get_snakemake_path():
+    return os.path.realpath(inspect.getmodule(inspect.stack()[1][0]).__file__)
+
+
 def main():
     parser = get_argument_parser()
     args = parser.parse_args()
+    
+    if args.bash_completion:
+        os.system("complete -C snakemake-bash-completion snakemake")
+        sys.exit(0)
 
-    snakemakepath = os.path.realpath(inspect.getmodule(inspect.stack()[1][0]).__file__)
+    snakemakepath = get_snakemake_path()
 
     try:
         resources = parse_resources(args)
         print(e, file=sys.stderr)
         print("", file=sys.stderr)
         parser.print_help()
-        return False
+        sys.exit(1)
 
     success = snakemake(
             args.snakefile,
             notemp=args.notemp,
             timestamp=args.timestamp)
     sys.exit(0 if success else 1)
+
+
+def bash_completion(snakefile="Snakefile"):
+    prefix = sys.argv[2]
+
+    if prefix.startswith("-"):
+        opts = [
+            action.option_strings[0] for action in get_argument_parser()._actions
+            if action.option_strings and action.option_strings[0].startswith(prefix)]
+        print(*opts, sep="\n")
+
+    else:
+        files = set(glob.glob("{}*".format(prefix)))
+        if files:
+            print(*sorted(files), sep="\n")
+        if os.path.exists(snakefile):
+            workflow = Workflow(snakefile=snakefile, snakemakepath=get_snakemake_path())
+            workflow.include(snakefile)
+
+            workflow_files = sorted(set(
+                file for file in workflow.concrete_files
+                if file.startswith(prefix) and file not in files))
+            if workflow_files:
+                print(*workflow_files, sep="\n")
+            
+            rules = [
+                rule.name for rule in workflow.rules
+                if rule.name.startswith(prefix)]
+            if rules:
+                print(*rules, sep="\n")
+    sys.exit(0)

File snakemake/io.py

         return set(match.group('name') for match in
             _wildcard_regex.finditer(self.file))
 
+    def contains_wildcard(self):
+        return _wildcard_regex.search(self.file) is not None
+
     def regex(self):
         if not self._regex:
             # compile a regular expression

File snakemake/workflow.py

     def rules(self):
         return self._rules.values()
 
+    @property
+    def concrete_files(self):
+        return (file for rule in self.rules for file in chain(rule.input, rule.output) if not callable(file) and not file.contains_wildcard())
+
     def check(self):
         for clause in self._ruleorder:
             for rulename in clause: