3838
3939from enum import Enum , IntFlag
4040from time import time
41+ from typing import NamedTuple
4142
4243from PyQt6 import sip
4344from PyQt6 .QtCore import (
@@ -2536,6 +2537,14 @@ def _skipToParagraph(self, step: int) -> None:
25362537 break
25372538
25382539
2540+ class CompleterAction (NamedTuple ):
2541+ """Values needed to complete a completer action."""
2542+
2543+ pos : int
2544+ length : int
2545+ value : str
2546+
2547+
25392548class CommandCompleter (QMenu ):
25402549 """GuiWidget: Command Completer Menu.
25412550
@@ -2552,6 +2561,7 @@ class CommandCompleter(QMenu):
25522561 def __init__ (self , parent : QWidget ) -> None :
25532562 super ().__init__ (parent = parent )
25542563 self ._parent = parent
2564+ self .triggered .connect (self ._emitComplete )
25552565
25562566 def updateMetaText (self , text : str , pos : int ) -> bool :
25572567 """Update the menu options based on the line of text."""
@@ -2583,7 +2593,7 @@ def updateMetaText(self, text: str, pos: int) -> bool:
25832593 for value in options :
25842594 rep = value + suffix
25852595 action = qtAddAction (self , value )
2586- action .triggered . connect ( qtLambda ( self . _emitComplete , offset , length , rep ))
2596+ action .setData ( CompleterAction ( pos = offset , length = length , value = rep ))
25872597
25882598 return True
25892599
@@ -2626,7 +2636,7 @@ def updateCommentText(self, text: str, pos: int) -> bool:
26262636 for value in options :
26272637 rep = value + suffix
26282638 action = qtAddAction (self , rep .rstrip (":. " ))
2629- action .triggered . connect ( qtLambda ( self . _emitComplete , offset , length , rep ))
2639+ action .setData ( CompleterAction ( pos = offset , length = length , value = rep ))
26302640 return True
26312641
26322642 return False
@@ -2639,28 +2649,35 @@ def keyPressEvent(self, event: QKeyEvent) -> None:
26392649 """Capture keypresses and forward most of them to the editor."""
26402650 match event .key ():
26412651 case Qt .Key .Key_Up | Qt .Key .Key_Down :
2652+ # Let the menu handle navigation
26422653 super ().keyPressEvent (event )
26432654 case Qt .Key .Key_Right | Qt .Key .Key_Return | Qt .Key .Key_Enter | Qt .Key .Key_Tab :
2655+ # Activate the selection if there is one, otherwise close the completer
26442656 if action := self .activeAction ():
26452657 action .trigger ()
26462658 else :
26472659 self .clear ()
26482660 self .close ()
26492661 case Qt .Key .Key_Left | Qt .Key .Key_Escape :
2662+ # Cancel the completer
26502663 self .clear ()
26512664 self .close ()
26522665 case _:
2666+ # Any other keys, send back to the editor
2667+ # Also close to release the event lock before forwarding key press (#2510)
26532668 self .clear ()
2654- self .close () # Close to release the event lock before forwarding key press (#2510)
2669+ self .close ()
26552670 self ._parent .keyPressEvent (event )
26562671
26572672 ##
2658- # Internal Functions
2673+ # Internal Slots
26592674 ##
26602675
2661- def _emitComplete (self , pos : int , length : int , value : str ) -> None :
2676+ @pyqtSlot (QAction )
2677+ def _emitComplete (self , action : QAction ) -> None :
26622678 """Emit the signal to indicate a selection has been made."""
2663- self .insertText .emit (pos , length , value )
2679+ if isinstance (data := action .data (), CompleterAction ):
2680+ self .insertText .emit (data .pos , data .length , data .value )
26642681
26652682
26662683class BackgroundWordCounter (QRunnable ):
0 commit comments