Editor right-click, outside current text selection, lose this selection



  • Code chunk 2/2:

    	def FindBorderBiDir(self, i_start, s_pattern):
    		i_text_len = editor.getTextLength()
    		t_search = editor.findText(FINDOPTION.REGEXP, i_start, 0, s_pattern)
    		if t_search is None:
    			i_left = -1
    		else:
    			i_left = t_search[0]
    		t_search = editor.findText(FINDOPTION.REGEXP, i_start, i_text_len, s_pattern)
    		if t_search is None:
    			i_right = i_text_len
    		else:
    			i_right = t_search[0]
    		return (i_left, i_right)
    
    	def ExtendSel_SpaceSpaceLike(self):
    		s_pattern = "\s"
    
    		i_caret_pos = editor.getCurrentPos()
    		i_start	= editor.getSelectionStart()
    		i_end	= editor.getSelectionEnd()
    
    		t_border = self.FindBorderBiDir(i_caret_pos, s_pattern)
    		i_left	= t_border[0] + 1
    		i_right	= t_border[1]
    		if i_left < i_right:
    			editor.setSel(i_left, i_right)
    		else:
    			editor.setSel(i_start, i_end)
    
    	def ExtendSel_AlphaNumUnderscoreDot(self):
    		s_pattern = "[^\w_.]"
    
    		i_caret_pos = editor.getCurrentPos()
    		i_start	= editor.getSelectionStart()
    		i_end	= editor.getSelectionEnd()
    
    		t_border = self.FindBorderBiDir(i_caret_pos, s_pattern)
    		i_left	= t_border[0] + 1
    		i_right	= t_border[1]
    		if i_left < i_right:
    			editor.setSel(i_left, i_right)
    		else:
    			editor.setSel(i_start, i_end)
    
    	def ExtendSel_Quotes(self):
    		i_text_len = editor.getTextLength()
    		i_caret_pos = editor.getCurrentPos()
    		i_start	= editor.getSelectionStart()
    		i_end	= editor.getSelectionEnd()
    
    		t_search_prev_single = editor.findText(0, i_caret_pos, 0, "'")
    		t_search_next_single = editor.findText(0, i_caret_pos, i_text_len, "'")
    		t_search_prev_double = editor.findText(0, i_caret_pos, 0, chr(34))
    		t_search_next_double = editor.findText(0, i_caret_pos, i_text_len, chr(34))
    
    		i_left	= None
    		i_right	= None
    		if ((t_search_prev_single is None) or (t_search_next_single is None)):
    			if (not(t_search_prev_double is None) and not(t_search_next_double is None)):
    				i_left	= t_search_prev_double[0] + 1
    				i_right	= t_search_next_double[0]
    		elif ((t_search_prev_double is None) or (t_search_next_double is None)):
    			if (not(t_search_prev_single is None) and not(t_search_next_single is None)):
    				i_left	= t_search_prev_single[0] + 1
    				i_right	= t_search_next_single[0]
    		elif t_search_prev_single[0] < t_search_prev_double[0]:
    				i_left	= t_search_prev_double[0] + 1
    				i_right	= t_search_next_double[0]
    		elif t_search_prev_double[0] < t_search_prev_single[0]:
    				i_left	= t_search_prev_single[0] + 1
    				i_right	= t_search_next_single[0]
    		if (not(i_left is None) and not(i_right is None)):
    			editor.setSel(i_left, i_right)
    		else:
    			editor.setSel(i_start, i_end)
    
    	def ExtendSel_BracketContent(self):
    		def SearchOrphan(i_start, i_end, s_pattern_brackets):
    			if i_start == i_end:
    				return None
    
    			if i_start < i_end: b_forward = True
    			else: b_forward = False
    
    			i_par = 0; i_sqr = 0; i_cur = 0
    			i_pos = i_start
    			while True:
    				t_search = editor.findText(FINDOPTION.REGEXP, i_pos, i_end, s_pattern_brackets)
    				if t_search is None:
    					return None
    
    				i_pos = t_search[0]
    				s_char = editor.getTextRange(i_pos, i_pos + 1)
    				if		s_char == "(": i_par += 1
    				elif	s_char == ")": i_par -= 1
    				elif	s_char == "[": i_sqr += 1
    				elif	s_char == "]": i_sqr -= 1
    				elif	s_char == "{": i_cur += 1
    				elif	s_char == "}": i_cur -= 1
    
    				if b_forward:
    					if (i_par < 0 or i_sqr < 0 or i_cur < 0): break
    				else:
    					if (i_par > 0 or i_sqr > 0 or i_cur > 0): break
    				if b_forward: i_pos = i_pos + 1
    			return (i_pos, s_char)
    
    		i_text_len = editor.getTextLength()
    		i_caret_pos = editor.getCurrentPos()
    		i_start	= editor.getSelectionStart()
    		i_end	= editor.getSelectionEnd()
    
    		s_pattern_par = "\(\)"
    		s_pattern_sqr = "[]"
    		s_pattern_cur = "\{\}"
    		s_pattern_brackets = "[" + s_pattern_par + s_pattern_sqr + s_pattern_cur + "]"
    
    		i_left	= None
    		i_right	= None
    		while True:
    			t_orphan_back = SearchOrphan(i_caret_pos, 0, s_pattern_brackets)
    			if t_orphan_back is None: break
    
    			s_char = t_orphan_back[1]
    			if		s_char == "(": s_pattern = "[" + s_pattern_par + "]"
    			elif	s_char == "[": s_pattern = "[" + s_pattern_sqr + "]"
    			elif	s_char == "{": s_pattern = "[" + s_pattern_cur + "]"
    			t_orphan_forward = SearchOrphan(i_caret_pos, i_text_len, s_pattern)
    			if not(t_orphan_forward is None):
    				i_left	= t_orphan_back[0] + 1
    				i_right	= t_orphan_forward[0]
    				break
    
    			if		s_char == "(": s_pattern_brackets = s_pattern_brackets.replace(s_pattern_par, "")
    			elif	s_char == "[": s_pattern_brackets = s_pattern_brackets.replace(s_pattern_sqr, "")
    			elif	s_char == "{": s_pattern_brackets = s_pattern_brackets.replace(s_pattern_cur, "")
    			if s_pattern_brackets == "[]": break
    		if (not(i_left is None) and not(i_right is None)):
    			editor.setSel(i_left, i_right)
    		else:
    			editor.setSel(i_start, i_end)
    	# end of class
    
    s_opt_info = ""
    if i_feature_shift_double_left_click			!= 1: s_opt_info = s_opt_info + "\t" + s_feature_sdlc_off + "\n"
    if i_feature_control_shift_double_left_click	!= 1: s_opt_info = s_opt_info + "\t" + s_feature_csdlc_off + "\n"
    if i_feature_alt_shift_double_left_click		!= 1: s_opt_info = s_opt_info + "\t" + s_feature_asdlc_off + "\n"
    if i_feature_alt_right_click					!= 1: s_opt_info = s_opt_info + "\t" + s_feature_arc_off + "\n"
    if i_feature_right_click						!= 1: s_opt_info = s_opt_info + "\t" + s_feature_rc_off + "\n"
    if not(s_opt_info == ""): s_opt_info = s_opt_info[:-1]
    console.editor.setProperty(s_editorprop_sdlc_active,	str(i_feature_shift_double_left_click))
    console.editor.setProperty(s_editorprop_csdlc_active,	str(i_feature_control_shift_double_left_click))
    console.editor.setProperty(s_editorprop_asdlc_active,	str(i_feature_alt_shift_double_left_click))
    console.editor.setProperty(s_editorprop_arc_active,		str(i_feature_alt_right_click))
    console.editor.setProperty(s_editorprop_rc_active,		str(i_feature_right_click))
    
    print "[" + s_script_name + " starts]"
    if console.editor.getProperty(s_editorprop_regdone) != s_true:
    	console.editor.setProperty(s_editorprop_active, s_true)
    	o_scint_mouse_click_hook = C_Scint_Mouse_Click_Hook()	# create an instance of the hook class
    	b_reg = o_scint_mouse_click_hook.RegHook()				# register the hook on all found Scintilla windows
    	if b_reg:
    		console.editor.setProperty(s_editorprop_regdone, s_true)
    		print "\t" + s_hook_name + " registered and activated (" + s_reruntogglehook + ")"
    		if not(s_opt_info == ""): print s_opt_info
    	else:
    		if not(s_opt_info == ""): print s_opt_info
    		print "\t" + s_hook_name + " registering failed"
    		if i_message_box_warnings == 1:
    			notepad.messageBox(s_hook_name + " registering failed", s_script_name, MESSAGEBOXFLAGS.ICONSTOP)
    else:
    	if console.editor.getProperty(s_editorprop_active) != s_true:
    		console.editor.setProperty(s_editorprop_active, s_true)
    		print "\t" + s_hook_name + " re-activated (" + s_reruntogglehook + ")"
    		if not(s_opt_info == ""): print s_opt_info
    		if i_message_box_warnings == 1:
    			notepad.messageBox( \
    				s_hook_name + " re-activated\n\n" + s_reruntogglehook + "\n" + s_willapplynewopt + "\n" + s_opt_info, \
    				s_script_name, MESSAGEBOXFLAGS.ICONINFORMATION)
    	else:
    		console.editor.setProperty(s_editorprop_active, "")
    		print "\t" + s_hook_name + " DE-ACTIVATED (" + s_reruntogglehook + ")"
    		if not(s_opt_info == ""): print s_opt_info
    		if i_message_box_warnings == 1:
    			notepad.messageBox( \
    				s_hook_name + " DE-ACTIVATED\n\n" + s_reruntogglehook + "\n" + s_willapplynewopt + "\n" + s_opt_info, \
    				s_script_name, MESSAGEBOXFLAGS.ICONEXCLAMATION)
    
    


  • Hey ! the forum changed the line 313 of my uploaded code

    line 313 was uploaded as :
    (I must replace \ by BKL to have it displayed)
    s_pattern_sqr = “BKL[BKL]”
    but is displayed without the \ as :
    s_pattern_sqr = “[]”

    which breaks the ‘CTRL + SHIFT + double-left-click’ feature : select brackets content : () [] {}

    having compared the whole uploaded code with my original code there should no other error
    (I used a simple file compare utility to do that : ExamDiff)

    So there is a bug in the text parser of the forum :
    the preview is ok but the final post has lost the backslashes



  • @frying-pan
    Wow, that’s quite a script. Maybe post to GitHub or a Gist and then link from here to that post?

    Cheers.



  • This post is deleted!


  • @Michael-Vincent

    Uploaded on GitHub the last posted script in this thread, as version v1 (without the backslash error)

    [https://github.com/frying-pan/NotepadPP-PythonScript-Mouse-Gesture/blob/master/Perso_ScintWndProc_Hook.v1.py](link url)

    and made a version v2.0 : with some code cleaning and more object_oriented style

    [https://github.com/frying-pan/NotepadPP-PythonScript-Mouse-Gesture/blob/master/Perso_ScintWndProc_Hook.v2.0.py](link url)



  • @frying-pan
    Because of file name changes, above links are not valid any more,
    see below for new links to each repository.



  • An update of :
    Perso_ScintWndProc_Hook_v1_0.py to Perso_ScintWndProc_Hook_v1_1.py and
    Perso_ScintWndProc_Hook_v2_0.py to Perso_ScintWndProc_Hook_v2.1.py for the same small bug

    Update to Perso_ScintWndProc_Hook_v3_0.py with new features :

    • option to select brackets/quotes with content
    • option to auto-copy selection to clipboard and/or console
    • expand selection from a previous selection
      -> now requires the two libraries : Perso__Lib_Edit.py, Perso__Lib_Window.py

    all files provided in the GitHub repository :
    https://github.com/frying-pan/NotepadPP-PythonScript-Mouse-Gesture

    ===

    And another small python script to tweak the CR and LF graphic :
    these changes can be applied at each Notepad++ start by running the script from startup.py

    Screenshot.jpg

    Perso_CrLfDisplay_Callback_v1_0.py

    file provided in the GitHub repository :
    https://github.com/frying-pan/NotepadPP-PythonScript-CrLf-Graphic-Tweak



  • I take advantage of this thread to advertise about two other python scripts that I wrote:

    +++

    Bracket Indicator : highlight the bracket () [] {} where is the selection/caret
    based on BracketHighlighter.py idea, with easier customization for highlight style,
    a different algo for highlighting (using the ‘re’ regexp object, possibly more efficient),
    following the brackets matching rules of Scintilla

    RestartNPP : to restart Notepad++ remembering the current session (opened file),
    can possibly made into a button, and be run with a keyboard shortcut via ‘Shortcut Mapper’
    can be handy when developping a script/plugin

    +++

    Perso_ScintWndProc_Hook was renamed to FP_MouseSelectGest_Hook, and updated
    Perso_CrLfDisplay_Callback was renamed to FP_CrLfDisplay_Callback, and updated

    FP_MouseSelectGest_Hook, FP_BracketIndicator_Callback and FP_CrLfDisplay_Callback
    can be run from startup.py on each NPP start (with pythonscript option : initialisation=ATSTARTUP)

    All four scripts have options at the top of the main script file that can be changed by the user
    Some of these scripts use libraries which are provided in the same Github folder as the main script

    Here is the root of the Github repositories :
    https://github.com/frying-pan?tab=repositories

    and the four repositories for the four scripts :
    https://github.com/frying-pan/NotepadPP-PythonScript-Mouse_Select_Gesture
    https://github.com/frying-pan/NotepadPP-PythonScript-Bracket_Indicator
    https://github.com/frying-pan/NotepadPP-PythonScript-Restart_NotepadPP
    https://github.com/frying-pan/NotepadPP-PythonScript-CrLf_Display



  • This thread got rather out of control.

    Anyway, I’m back to say that I did change my mind and I like the very first basic functionality this thread introduced: The ability to not lose your selection if you right click somewhere not on that selection.

    However, I noticed that it isn’t compatible with one of the new features of Notepad++: The ability go right-click the bookmark margin and get a right-click popup menu of bookmarking functions.

    I like the idea of both features; I wonder if there is some way to get both functionalities. Hmmm…



  • @Alan-Kilborn

    "This thread got rather out of control."

    I could create a separate thread to describe and post the links for the 4 scripts I have made available on Github

    "However, I noticed that it isn’t compatible with one of the new features of Notepad++: The ability go right-click the bookmark margin and get a right-click popup menu of bookmarking functions."

    I have NPP 7.8.2 and the right-click on the bookmark margin has been introduced later, so I can not test this for the moment
    (I guess the right-click context-menu on the bookmark margin does not appear at all…)

    I could discriminate between right-clicks on the margin or the text by pixel position,
    I will need the widths in pixels of all left margins :
    the function “editor.getMarginWidthN(margin_index) → int”, gives that for each margin_index,
    but I don’t know how many of margin_indexes must be checked (probably 5, from 0 to SC_MAX_MARGIN (4)),
    the function SCI_GETMARGINS (that gives the number of margins) seems to be missing from the NPP Scintilla commands

    Possible workarounds :
    My script does not intercept shift+right-click, so it could be tried on the bookmark margin
    (in case this context-menu is not sensitive to the shift key, which is often the case for context-menus)

    Also control+right-click and alt+right-click can be disabled in my script
    (there is a middle-click alternative for these features)
    to see if they trigger the bookmark margin context-menu, which seems less likely…



  • @frying-pan

    I noticed that the feature that this thread started with is being implemented natively in Notepad++. See HERE.



  • @Alan-Kilborn

    ok i see
    [https://github.com/notepad-plus-plus/notepad-plus-plus/pull/8564](link url)
    ‘Keep selection when right-click outside of selection’ has been added, or will be added to the next NPP version (as an option).

    So I will remove this specific feature from my
    NotepadPP-PythonScript-Mouse_Select_Gesture script
    once I have updated my NPP and tested the native option.


Log in to reply