Beispiel #1
0
    def visitcommand(self, node, parts):
        assert parts

        # look for the first WordNode, which might not be at parts[0]
        idxwordnode = parser.findfirstkind(parts, 'word')
        if idxwordnode == -1:
            logger.info('no words found in command (probably contains only redirects)')
            return

        # we're mutating the parts of node, causing the visitor to skip the nodes
        # we're popping
        wordnode = parts.pop(idxwordnode)
        name = 'command%d' % len([g for g in self.groups if g.name.startswith('command')])
        startpos, endpos = wordnode.pos

        try:
            mps = self.findmanpages(wordnode.word)
        except errors.ProgramDoesNotExist, e:
            logger.info('no manpage found for %r', wordnode.word)

            mg = matchgroup(name)
            mg.error = e
            mg.manpage = None
            mg.suggestions = None
            self.groups.append(mg)

            self.matches.append(matchresult(startpos, endpos, None, None))
            return
Beispiel #2
0
    def startcommand(self, parts, endword, addunknown=True):
        logger.info('startcommand parts=%r, endword=%r, addunknown=%s', parts,
                    endword, addunknown)
        idxwordnode = parser.findfirstkind(parts, 'word')
        assert idxwordnode != -1

        wordnode = parts.pop(idxwordnode)
        name = 'command%d' % len(
            [g for g in self.groups if g.name.startswith('command')])
        startpos, endpos = wordnode.pos

        try:
            mps = self.findmanpages(wordnode.word)
        except errors.ProgramDoesNotExist, e:
            if addunknown:
                logger.info('no manpage found for %r, marking it unknown',
                            wordnode.word)

                mg = matchgroup(name)
                mg.error = e
                mg.manpage = None
                mg.suggestions = None
                self.groups.append(mg)
                self.groupstack.append((mg, endword))

                self.matches.append(matchresult(startpos, endpos, None, None))

            return False
Beispiel #3
0
    def startcommand(self, parts, endword, addunknown=True):
        logger.info('startcommand parts=%r, endword=%r, addunknown=%s',
                    parts, endword, addunknown)
        idxwordnode = parser.findfirstkind(parts, 'word')
        assert idxwordnode != -1

        wordnode = parts.pop(idxwordnode)
        name = 'command%d' % len([g for g in self.groups if g.name.startswith('command')])
        startpos, endpos = wordnode.pos

        try:
            mps = self.findmanpages(wordnode.word)
        except errors.ProgramDoesNotExist, e:
            if addunknown:
                logger.info('no manpage found for %r, marking it unknown', wordnode.word)

                mg = matchgroup(name)
                mg.error = e
                mg.manpage = None
                mg.suggestions = None
                self.groups.append(mg)
                self.groupstack.append((mg, endword))

                self.matches.append(matchresult(startpos, endpos, None, None))

            return False
Beispiel #4
0
    def visitcommand(self, node, parts):
        assert parts

        # look for the first WordNode, which might not be at parts[0]
        idxwordnode = parser.findfirstkind(parts, 'word')
        if idxwordnode == -1:
            logger.info('no words found in command (probably contains only redirects)')
            return

        self.startcommand(parts, None)
        return len(self.groupstack)
Beispiel #5
0
class matcher(parser.NodeVisitor):
    '''parse a command line and return a list of matchresults describing
    each token.
    '''
    def __init__(self, s, store):
        self.s = s.encode('latin1', 'replace')
        self.store = store
        self._prevoption = self._currentoption = None
        self.groups = [matchgroup('shell')]

        # a stack to manage nested command groups: whenever a new simple command
        # is started, we push it to the stack and when it ends we pop it. the second
        # item in the tuple is used to end the top-most command when it is equal
        # to the current word. this is used when a flag starts a new command, e.g.
        # find -exec.
        self.groupstack = [(self.groups[-1], None)]

    @property
    def matches(self):
        '''return the list of results from the most recently created group'''
        return self.groupstack[-1][0].results

    @property
    def allmatches(self):
        return list(
            itertools.chain.from_iterable(g.results for g in self.groups))

    @property
    def manpage(self):
        return self.groupstack[-1][0].manpage

    def find_option(self, opt):
        self._currentoption = self.manpage.find_option(opt)
        logger.debug('looking up option %r, got %r', opt, self._currentoption)
        return self._currentoption

    def findmanpages(self, prog):
        prog = prog.decode('latin1')
        logger.info('looking up %r in store', prog)
        manpages = self.store.findmanpage(prog)
        logger.info('found %r in store, got: %r, using %r', prog, manpages,
                    manpages[0])
        return manpages

    def unknown(self, token, start, end):
        logger.debug('nothing to do with token %r', token)
        return matchresult(start, end, None, None)

    def visitnegate(self, node):
        helptext = helpconstants.NEGATE
        self.groups[0].results.append(
            matchresult(node.pos[0], node.pos[1], helptext, None))

    def visitoperator(self, node, op):
        helptext = helpconstants.OPERATORS[op]
        self.groups[0].results.append(
            matchresult(node.pos[0], node.pos[1], helptext, None))

    def visitpipe(self, node, pipe):
        self.groups[0].results.append(
            matchresult(node.pos[0], node.pos[1], helpconstants.PIPELINES,
                        None))

    def visitredirect(self, node, input, type, output):
        helptext = [helpconstants.REDIRECTION]

        if type in helpconstants.REDIRECTION_KIND:
            helptext.append(helpconstants.REDIRECTION_KIND[type])

        self.groups[0].results.append(
            matchresult(node.pos[0], node.pos[1], '\n\n'.join(helptext), None))

    def visitcompound(self, node, group, list, redirects):
        helptext = helpconstants.COMPOUND[group]
        # we add a matchresult for the start and end of the compound command
        self.groups[0].results.append(
            matchresult(node.pos[0], node.pos[0] + 1, helptext, None))
        self.groups[0].results.append(
            matchresult(node.pos[1] - 1, node.pos[1], helptext, None))

    def visitcommand(self, node, parts):
        assert parts

        # look for the first WordNode, which might not be at parts[0]
        idxwordnode = parser.findfirstkind(parts, 'word')
        if idxwordnode == -1:
            logger.info(
                'no words found in command (probably contains only redirects)')
            return

        self.startcommand(parts, None)
        return len(self.groupstack)

    def visitcommandend(self, node, parts, prevstackdepth):
        # it's possible for visitcommand/end to be called without a command group
        # being pushed if it contains only redirect nodes
        if len(self.groupstack) > 1:
            if prevstackdepth != len(self.groupstack):
                logger.info('group %s is a result of a nested command',
                            self.groupstack[-1])
                self.endcommand()
            self.endcommand()

    def startcommand(self, parts, endword, addunknown=True):
        logger.info('startcommand parts=%r, endword=%r, addunknown=%s', parts,
                    endword, addunknown)
        idxwordnode = parser.findfirstkind(parts, 'word')
        assert idxwordnode != -1

        wordnode = parts.pop(idxwordnode)
        name = 'command%d' % len(
            [g for g in self.groups if g.name.startswith('command')])
        startpos, endpos = wordnode.pos

        try:
            mps = self.findmanpages(wordnode.word)
        except errors.ProgramDoesNotExist, e:
            if addunknown:
                logger.info('no manpage found for %r, marking it unknown',
                            wordnode.word)

                mg = matchgroup(name)
                mg.error = e
                mg.manpage = None
                mg.suggestions = None
                self.groups.append(mg)
                self.groupstack.append((mg, endword))

                self.matches.append(matchresult(startpos, endpos, None, None))

            return False

        manpage = mps[0]
        idxnextwordnode = parser.findfirstkind(parts, 'word')

        if manpage.multicommand and idxnextwordnode != -1:
            nextwordnode = parts[idxnextwordnode]
            try:
                multi = '%s %s' % (wordnode.word, nextwordnode.word)
                logger.info(
                    '%r is a multicommand, trying to get another token and look up %r',
                    manpage, multi)
                mps = self.findmanpages(multi)
                manpage = mps[0]
                parts.pop(idxnextwordnode)
                endpos = nextwordnode.pos[1]
            except errors.ProgramDoesNotExist:
                logger.info('no manpage %r for multicommand %r', multi,
                            manpage)

        # create a new matchgroup for the current command
        mg = matchgroup(name)
        mg.manpage = manpage
        mg.suggestions = mps[1:]
        self.groups.append(mg)
        self.groupstack.append((mg, endword))

        self.matches.append(
            matchresult(startpos, endpos, manpage.synopsis, None))
        return True