def computeSmartIndent(self, block, ch):
        """indent gets three arguments: line, indentWidth in spaces,
        typed character indent
        """
        if not self._isValidTrigger(block, ch):
            return None

        prevStmt = self.findPrevStmt(block)
        if not prevStmt.endBlock.isValid():
            return None  # Can't indent the first line

        prevBlock = self._prevNonEmptyBlock(block)

        # HACK Detect here documents
        if self._qpart.isHereDoc(prevBlock.blockNumber(), prevBlock.length() - 2):
          return None

        # HACK Detect embedded comments
        if self._qpart.isBlockComment(prevBlock.blockNumber(), prevBlock.length() - 2):
            return None

        prevStmtCnt = prevStmt.content()
        prevStmtInd = prevStmt.indent()

        # Are we inside a parameter list, array or hash?
        foundBlock, foundColumn, foundChar = self.lastAnchor(block, 0)
        if foundBlock is not None:
            shouldIndent = foundBlock == prevStmt.endBlock or \
                           self.testAtEnd(prevStmt, re.compile(',\s*'))
            if (not self._isLastCodeColumn(foundBlock, foundColumn)) or \
                self.lastAnchor(foundBlock, foundColumn)[0] is not None:
                # TODO This is alignment, should force using spaces instead of tabs:
                if shouldIndent:
                    foundColumn += 1
                    nextCol = self._nextNonSpaceColumn(foundBlock, foundColumn)
                    if nextCol > 0 and \
                       (not self._isComment(foundBlock, nextCol)):
                        foundColumn = nextCol

                # Keep indent of previous statement, while aligning to the anchor column
                if len(prevStmtInd) > foundColumn:
                    return prevStmtInd
                else:
                    return self._makeIndentAsColumn(foundBlock, foundColumn)
            else:
                indent = self._blockIndent(foundBlock)
                if shouldIndent:
                    indent = self._increaseIndent(indent)
                return indent

        # Handle indenting of multiline statements.
        if (prevStmt.endBlock == block.previous() and \
             self._isBlockContinuing(prevStmt.endBlock)) or \
           self.isStmtContinuing(prevStmt.endBlock):
            if prevStmt.startBlock == prevStmt.endBlock:
                if ch == '' and \
                   len(self._blockIndent(block)) > len(self._blockIndent(prevStmt.endBlock)):
                    return None  # Don't force a specific indent level when aligning manually
                return self._increaseIndent(self._increaseIndent(prevStmtInd))
            else:
                return self._blockIndent(prevStmt.endBlock)

        if rxUnindent.match(block.text()):
            startStmt = self.findBlockStart(block)
            if startStmt.startBlock.isValid():
                return startStmt.indent()
            else:
                return None

        if self.isBlockStart(prevStmt) and not rxBlockEnd.search(prevStmt.content()):
            return self._increaseIndent(prevStmtInd)
        elif re.search(r'[\[\{]\s*$', prevStmtCnt) is not None:
            return self._increaseIndent(prevStmtInd)

        # Keep current
        return prevStmtInd
indent gets three arguments: line, indentWidth in spaces,
        typed character indent