예제 #1
0
    def do_test(self):
        selections = []
        self.match_locs = []

        class Pos:
            python: int = 0
            qt: int = 0

        if self.regex_valid():
            text = str(self.preview.toPlainText())
            regex = str(self.regex.text())
            cursor = QTextCursor(self.preview.document())
            extsel = QTextEdit.ExtraSelection()
            extsel.cursor = cursor
            extsel.format.setBackground(QBrush(Qt.GlobalColor.yellow))
            with suppress(Exception):
                prev = Pos()
                for match in compile_regular_expression(regex).finditer(text):
                    es = QTextEdit.ExtraSelection(extsel)
                    qtchars_to_start = utf16_length(
                        text[prev.python:match.start()])
                    qt_pos = prev.qt + qtchars_to_start
                    prev.python = match.end()
                    prev.qt = qt_pos + utf16_length(match.group())
                    es.cursor.setPosition(qt_pos,
                                          QTextCursor.MoveMode.MoveAnchor)
                    es.cursor.setPosition(prev.qt,
                                          QTextCursor.MoveMode.KeepAnchor)
                    selections.append(es)
                    self.match_locs.append((qt_pos, prev.qt))
        self.preview.setExtraSelections(selections)
        if self.match_locs:
            self.next.setEnabled(True)
            self.previous.setEnabled(True)
        self.occurrences.setText(str(len(self.match_locs)))
 def do_test(self):
     selections = []
     self.match_locs = []
     if self.regex_valid():
         text = unicode_type(self.preview.toPlainText())
         regex = unicode_type(self.regex.text())
         cursor = QTextCursor(self.preview.document())
         extsel = QTextEdit.ExtraSelection()
         extsel.cursor = cursor
         extsel.format.setBackground(QBrush(Qt.GlobalColor.yellow))
         try:
             for match in compile_regular_expression(regex).finditer(text):
                 es = QTextEdit.ExtraSelection(extsel)
                 es.cursor.setPosition(match.start(),
                                       QTextCursor.MoveMode.MoveAnchor)
                 es.cursor.setPosition(match.end(),
                                       QTextCursor.MoveMode.KeepAnchor)
                 selections.append(es)
                 self.match_locs.append((match.start(), match.end()))
         except:
             pass
     self.preview.setExtraSelections(selections)
     if self.match_locs:
         self.next.setEnabled(True)
         self.previous.setEnabled(True)
     self.occurrences.setText(unicode_type(len(self.match_locs)))
예제 #3
0
    def reformat_blocks(self, position, removed, added):
        doc = self.doc
        if doc is None or self.ignore_requests or not hasattr(self, 'state_map'):
            return

        block = doc.findBlock(position)
        if not block.isValid():
            return
        start_cursor = QTextCursor(block)
        last_block = doc.findBlock(position + added + (1 if removed > 0 else 0))
        if not last_block.isValid():
            last_block = doc.lastBlock()
        end_cursor = QTextCursor(last_block)
        end_cursor.movePosition(QTextCursor.MoveOperation.EndOfBlock)
        self.requests.append((start_cursor, end_cursor))
        QTimer.singleShot(0, self.do_one_block)
예제 #4
0
 def copy_lines(self, lo, hi, cursor):
     ''' Copy specified lines from the syntax highlighted buffer into the
     destination cursor, preserving all formatting created by the syntax
     highlighter. '''
     self.highlighter.join()
     num = hi - lo
     if num > 0:
         block = self.findBlockByNumber(lo)
         while num > 0:
             num -= 1
             cursor.insertText(block.text())
             dest_block = cursor.block()
             c = QTextCursor(dest_block)
             try:
                 afs = block.layout().additionalFormats()
             except AttributeError:
                 afs = ()
             for af in afs:
                 start = dest_block.position() + af.start
                 c.setPosition(start), c.setPosition(
                     start + af.length, QTextCursor.MoveMode.KeepAnchor)
                 c.setCharFormat(af.format)
             cursor.insertBlock()
             cursor.setCharFormat(NULL_FMT)
             block = block.next()
예제 #5
0
 def goto_loc(self,
              loc,
              operation=QTextCursor.MoveOperation.Right,
              mode=QTextCursor.MoveMode.KeepAnchor,
              n=0):
     cursor = QTextCursor(self.preview.document())
     cursor.setPosition(loc)
     if n:
         cursor.movePosition(operation, mode, n)
     self.preview.setTextCursor(cursor)
예제 #6
0
 def set_document(self, doc, doc_name=None):
     old_doc = self.doc
     if old_doc is not None:
         old_doc.contentsChange.disconnect(self.reformat_blocks)
         c = QTextCursor(old_doc)
         c.beginEditBlock()
         blk = old_doc.begin()
         while blk.isValid():
             blk.layout().clearAdditionalFormats()
             blk = blk.next()
         c.endEditBlock()
     self.doc = self.doc_name = None
     if doc is not None:
         self.doc = doc
         self.doc_name = doc_name
         doc.contentsChange.connect(self.reformat_blocks)
         self.rehighlight()
예제 #7
0
    def show_context_menu(self, pos):
        m = QMenu(self)
        a = m.addAction
        c = self.editor.cursorForPosition(pos)
        origc = QTextCursor(c)
        current_cursor = self.editor.textCursor()
        r = origr = self.editor.syntax_range_for_cursor(c)
        if (
                r is None or not r.format.property(SPELL_PROPERTY)
        ) and c.positionInBlock() > 0 and not current_cursor.hasSelection():
            c.setPosition(c.position() - 1)
            r = self.editor.syntax_range_for_cursor(c)

        if r is not None and r.format.property(SPELL_PROPERTY):
            word = self.editor.text_for_range(c.block(), r)
            locale = self.editor.spellcheck_locale_for_cursor(c)
            orig_pos = c.position()
            c.setPosition(orig_pos - utf16_length(word))
            found = False
            self.editor.setTextCursor(c)
            if self.editor.find_spell_word([word],
                                           locale.langcode,
                                           center_on_cursor=False):
                found = True
                fc = self.editor.textCursor()
                if fc.position() < c.position():
                    self.editor.find_spell_word([word],
                                                locale.langcode,
                                                center_on_cursor=False)
            spell_cursor = self.editor.textCursor()
            if current_cursor.hasSelection():
                # Restore the current cursor so that any selection is preserved
                # for the change case actions
                self.editor.setTextCursor(current_cursor)
            if found:
                suggestions = dictionaries.suggestions(word, locale)[:7]
                if suggestions:
                    for suggestion in suggestions:
                        ac = m.addAction(
                            suggestion,
                            partial(self.editor.simple_replace,
                                    suggestion,
                                    cursor=spell_cursor))
                        f = ac.font()
                        f.setBold(True), ac.setFont(f)
                    m.addSeparator()
                m.addAction(actions['spell-next'])
                m.addAction(_('Ignore this word'),
                            partial(self._nuke_word, None, word, locale))
                dics = dictionaries.active_user_dictionaries
                if len(dics) > 0:
                    if len(dics) == 1:
                        m.addAction(
                            _('Add this word to the dictionary: {0}').format(
                                dics[0].name),
                            partial(self._nuke_word, dics[0].name, word,
                                    locale))
                    else:
                        ac = m.addAction(_('Add this word to the dictionary'))
                        dmenu = QMenu(m)
                        ac.setMenu(dmenu)
                        for dic in dics:
                            dmenu.addAction(
                                dic.name,
                                partial(self._nuke_word, dic.name, word,
                                        locale))
                m.addSeparator()

        if origr is not None and origr.format.property(LINK_PROPERTY):
            href = self.editor.text_for_range(origc.block(), origr)
            m.addAction(
                _('Open %s') % href, partial(self.link_clicked.emit, href))

        if origr is not None and (origr.format.property(TAG_NAME_PROPERTY)
                                  or origr.format.property(CSS_PROPERTY)):
            word = self.editor.text_for_range(origc.block(), origr)
            item_type = 'tag_name' if origr.format.property(
                TAG_NAME_PROPERTY) else 'css_property'
            url = help_url(word,
                           item_type,
                           self.editor.highlighter.doc_name,
                           extra_data=current_container().opf_version)
            if url is not None:
                m.addAction(
                    _('Show help for: %s') % word, partial(open_url, url))

        for x in ('undo', 'redo'):
            ac = actions['editor-%s' % x]
            if ac.isEnabled():
                a(ac)
        m.addSeparator()
        for x in ('cut', 'copy', 'paste'):
            ac = actions['editor-' + x]
            if ac.isEnabled():
                a(ac)
        m.addSeparator()
        m.addAction(_('&Select all'), self.editor.select_all)
        if self.selected_text or self.has_marked_text:
            update_mark_text_action(self)
            m.addAction(actions['mark-selected-text'])
        if self.syntax != 'css' and actions['editor-cut'].isEnabled():
            cm = QMenu(_('Change &case'), m)
            for ac in 'upper lower swap title capitalize'.split():
                cm.addAction(actions['transform-case-' + ac])
            m.addMenu(cm)
        if self.syntax == 'html':
            m.addAction(actions['multisplit'])
        m.exec_(self.editor.viewport().mapToGlobal(pos))
예제 #8
0
    def resized(self):
        ' Resize images to fit in new view size and adjust all line number references accordingly '
        for v in (self.left, self.right):
            changes = []
            for i, (top, bot, kind) in enumerate(v.changes):
                if top in v.images:
                    img, oldw, oldlines = v.images[top]
                    lines, w = self.get_lines_for_image(img, v)
                    if lines != oldlines:
                        changes.append((i, lines, lines - oldlines, img, w))

            for i, lines, delta, img, w in changes:
                top, bot, kind = v.changes[i]
                c = QTextCursor(v.document().findBlockByNumber(top+1))
                c.beginEditBlock()
                c.movePosition(QTextCursor.MoveOperation.StartOfBlock)
                if delta > 0:
                    for _ in range(delta):
                        c.insertBlock()
                else:
                    c.movePosition(QTextCursor.MoveOperation.NextBlock, QTextCursor.MoveMode.KeepAnchor, -delta)
                    c.removeSelectedText()
                c.endEditBlock()
                v.images[top] = (img, w, lines)

                def mapnum(x):
                    return x if x <= top else x + delta
                lnm = LineNumberMap()
                lnm.max_width = v.line_number_map.max_width
                for x, val in iteritems(v.line_number_map):
                    dict.__setitem__(lnm, mapnum(x), val)
                v.line_number_map = lnm
                v.changes = [(mapnum(t), mapnum(b), k) for t, b, k in v.changes]
                v.headers = [(mapnum(x), name) for x, name in v.headers]
                v.images = OrderedDict((mapnum(x), v) for x, v in iteritems(v.images))
            v.viewport().update()
예제 #9
0
 def search(self, query, reverse=False):
     ''' Search for query, also searching the headers. Matches in headers
     are not highlighted as managing the highlight is too much of a pain.'''
     if not query.strip():
         return
     c = self.textCursor()
     lnum = c.block().blockNumber()
     cpos = c.positionInBlock()
     headers = dict(self.headers)
     if lnum in headers:
         cpos = self.search_header_pos
     lines = unicode_type(self.toPlainText()).splitlines()
     for hn, text in self.headers:
         lines[hn] = text
     prefix, postfix = lines[lnum][:cpos], lines[lnum][cpos:]
     before, after = enumerate(lines[0:lnum]), ((lnum+1+i, x) for i, x in enumerate(lines[lnum+1:]))
     if reverse:
         sl = chain([(lnum, prefix)], reversed(tuple(before)), reversed(tuple(after)), [(lnum, postfix)])
     else:
         sl = chain([(lnum, postfix)], after, before, [(lnum, prefix)])
     flags = regex.REVERSE if reverse else 0
     pat = regex.compile(regex.escape(query, special_only=True), flags=regex.UNICODE|regex.IGNORECASE|flags)
     for num, text in sl:
         try:
             m = next(pat.finditer(text))
         except StopIteration:
             continue
         start, end = m.span()
         length = end - start
         if text is postfix:
             start += cpos
         c = QTextCursor(self.document().findBlockByNumber(num))
         c.setPosition(c.position() + start)
         if num in headers:
             self.search_header_pos = start + length
         else:
             c.setPosition(c.position() + length, QTextCursor.MoveMode.KeepAnchor)
             self.search_header_pos = 0
         if reverse:
             pos, anchor = c.position(), c.anchor()
             c.setPosition(pos), c.setPosition(anchor, QTextCursor.MoveMode.KeepAnchor)
         self.setTextCursor(c)
         self.centerCursor()
         self.scrolled.emit()
         break
     else:
         info_dialog(self, _('No matches found'), _(
             'No matches found for query: %s' % query), show=True)
예제 #10
0
    def find_text(self, pat, cursor, reverse):
        from calibre.gui2.tweak_book.text_search import find_text_in_chunks
        chunks = []

        cstart = min(cursor.position(), cursor.anchor())
        cend = max(cursor.position(), cursor.anchor())
        if reverse:
            cend -= 1
        c = QTextCursor(cursor)
        c.setPosition(cstart)
        block = c.block()
        in_text = find_tag_definition(block, 0)[0] is None
        if in_text:
            # Check if we are in comment/PI/etc.
            pb = block.previous()
            while pb.isValid():
                boundaries = pb.userData().non_tag_structures
                if boundaries:
                    if boundaries[-1].is_start:
                        in_text = False
                    break
                pb = pb.previous()

        def append(text, start):
            text = text.replace(PARAGRAPH_SEPARATOR, '\n')
            after = start + len(text)
            if start <= cend and cstart < after:
                extra = after - (cend + 1)
                if extra > 0:
                    text = text[:-extra]
                extra = cstart - start
                if extra > 0:
                    text = text[extra:]
                chunks.append((text, start + max(extra, 0)))

        while block.isValid() and block.position() <= cend:
            ud = block.userData()
            boundaries = sorted(chain(ud.tags, ud.non_tag_structures),
                                key=get_offset)
            if not boundaries:
                # Add the whole line
                if in_text:
                    text = block.text() + '\n'
                    append(text, block.position())
            else:
                start = block.position()
                c.setPosition(start)
                for b in boundaries:
                    if in_text:
                        c.setPosition(start + b.offset,
                                      QTextCursor.MoveMode.KeepAnchor)
                        if c.hasSelection():
                            append(c.selectedText(), c.anchor())
                    in_text = not b.is_start
                    c.setPosition(start + b.offset + 1)
                if in_text:
                    # Add remaining text in block
                    c.setPosition(block.position() + boundaries[-1].offset + 1)
                    c.movePosition(QTextCursor.MoveOperation.EndOfBlock,
                                   QTextCursor.MoveMode.KeepAnchor)
                    if c.hasSelection():
                        append(c.selectedText() + '\n', c.anchor())
            block = block.next()
        s, e = find_text_in_chunks(pat, chunks)
        return s != -1 and e != -1, s, e
예제 #11
0
def apply_smart_comment(editor, opening='/*', closing='*/', line_comment=None):
    doc = editor.document()
    c = QTextCursor(editor.textCursor())
    c.clearSelection()
    before_opening = doc.find(
        opening, c, QTextDocument.FindFlag.FindBackward
        | QTextDocument.FindFlag.FindCaseSensitively)
    before_closing = doc.find(
        closing, c, QTextDocument.FindFlag.FindBackward
        | QTextDocument.FindFlag.FindCaseSensitively)
    after_opening = doc.find(opening, c,
                             QTextDocument.FindFlag.FindCaseSensitively)
    after_closing = doc.find(closing, c,
                             QTextDocument.FindFlag.FindCaseSensitively)
    in_block_comment = (not before_opening.isNull() and (before_closing.isNull() or before_opening.position() >= before_closing.position())) and \
        (not after_closing.isNull() and (after_opening.isNull() or after_closing.position() <= after_opening.position()))
    if in_block_comment:
        before_opening.removeSelectedText(), after_closing.removeSelectedText()
        return
    c = QTextCursor(editor.textCursor())
    left, right = min(c.position(), c.anchor()), max(c.position(), c.anchor())
    c.beginEditBlock()
    c.setPosition(right), c.insertText(closing)
    c.setPosition(left), c.insertText(opening)
    c.endEditBlock()