import sys
import os
from PyQt5.QtWidgets import QApplication
from PyQt5.QtCore import Qt, QEvent
from PyQt5.QtGui import QTextCursor, QTextDocument
from PyQt5.QtWidgets import QPlainTextEdit
doctext = '''
         Documenting that QTextDocument Undo
        does not properly restore QTextCursor
     when replaced text spans the cursor position

1. Alternate ctl-1 ctl-2 (Mac: cmd-1 cmd-2)
   Observe moving between bookmark 1 and 2.

>>1<< bookmark 1

2. Delete this whole line.

3. Alternate ctl-1 ctl-2, observe that
   bookmark 2 textcursor correctly updated.

4. Key ctl-z (Mac: cmd-z) to restore deleted line.

5. Alternate ctl-1 ctl-2, observe bookmark 2
   is still correct.

>>2<< bookmark 2

6. Drag-select the characters ">2<" and hit Delete.
    key ctl-2: observe bookmark selection adjusted.

7. ctl-z, ctl-2: bookmark restored correctly.

8. Drag-select "2<< bookmark" and hit Delete.
   key ctl-2: bookmark adjusted to remaining data ">>".

9. ctl-z, ctl-2: BOOKMARK NOT CORRECTLY RESTORED!

10. Drag-select all lines from "5. ..." through line "6..."
    and key some replacement text e.g. "asdfasdf"

11. ctl-2, bookmark has no selection, has moved
    to end of modified span -- this is reasonable.

12. ctl-z (twice, why?) to restore original text.
    key ctl-2: BOOKMARK NOT RESTORED! It's still at
    end of modified span and no selection.
'''

class MyEditor(QPlainTextEdit):
        def __init__(self,doctext):
                super().__init__()
                self.document().setPlainText(doctext)
                self.setMinimumSize(500,500)
                self.tc1 = self.document().find('>>1<<')
                self.tc2 = self.document().find('>>2<<')
                tc = QTextCursor(self.document())
                tc.setPosition(0)
                self.setTextCursor(tc)

        def keyPressEvent(self, event):
                if event.modifiers() & Qt.ControlModifier :
                        if event.key() == Qt.Key_1 : # ^1 for bookmark 1
                                event.accept()
                                self.setTextCursor(self.tc1)
                                print('tc1 pos {0} anchor {1}'.format(
                                        self.tc1.position(),self.tc1.anchor() ) )
                                return
                        elif event.key() == Qt.Key_2 : # ^2 for bookmark 2
                                event.accept()
                                self.setTextCursor(self.tc2)
                                print( 'tc2 pos {0} anchor {1}'.format(
                                        self.tc2.position(),self.tc2.anchor() ) )
                                return
                        # else some other ^key, pass it on
                # else not control-key
                super().keyPressEvent(event)

qapp = QApplication(sys.argv)

editor = MyEditor(doctext)
editor.show()

qapp.exec_()