Calltip on mouse-over from UDL xml file (Python)
-
I’ve decided to go with only 1 “Overload” entry per keyword for the time being. I couldn’t find any clear documentation or examples on how to implement them, if anyone has any experience with this… I’m all ears. Unless its to add multiple overloads, this will be the “final” version of the script. A bit funny that it turned out to be “on character” and not “mouse-over”… :)
Something weird I noticed while testing with the multiple overloads, when the calltip is showing and I use the “alt up” and “alt down” shortcuts it crashes Notepad++ to desktop. Even with the script below that only has 1 “Overload” entry it CTD, clicking on the calltip doesn’t crash btw. I have no idea why it does this, I disabled the parameter hint shortcuts, and recommend it to anyone who wants to use the script below until the cause is found.
I changed the script to work on a “space” instead of mouse-over, but it can easily be changed to any character you want. I added explanations in the comments on how to edit the script to work with any User Defined Language, and how to change the character that triggers the calltip. Formatted the calltip some more and cleaned the script up, if anyone needs help to get it running… don’t hesistate to ask.
<NotepadPlus> <AutoComplete language=""> <Environment ignoreCase="yes"/> <KeyWord name="AddAmmoEffect" func="yes"> <Overload retVal="(successful:0/1)" descr=' 
Adds an ammo effect to an ammo type. 
------ 
Syntax 
------ 
(successful:0/1) AddAmmoEffect ammo:ref ammoEffect:ref 
------- 
Example 
------- 
AddAmmoEffect Ammo12Ga AmmoEffectBeanBagFatigue '> <Param name="Form:AnyForm"/> </Overload> </KeyWord> </AutoComplete> </NotepadPlus>
# Calltip on any character from __future__ import print_function # Import the required modules import xml.etree.ElementTree as ET from collections import defaultdict import textwrap # Import and parse the data from file tree = ET.parse("PATH/TO/YOUR/AUTOCOMPLETE.XML") root = tree.getroot() # Create empty dictionary data_dict = {} # Imoort the XML data into a Python dictionary def etree_to_dict(t): d = {t.tag: {} if t.attrib else None} children = list(t) if children: dd = defaultdict(list) for dc in map(etree_to_dict, children): for k, v in dc.items(): dd[k].append(v) d = {t.tag: {k: v[0] if len(v) == 1 else v for k, v in dd.items()}} if t.attrib: d[t.tag].update(("" + k, v) for k, v in t.attrib.items()) if t.text: text = t.text.strip() if children or t.attrib: if text: d[t.tag]["#text"] = text else: d[t.tag] = text return d data_dict = etree_to_dict(root) # Padding for the calltip pad = "----------------------------------------------------------------------" # Clear callbacks editor.clearCallbacks() # Get word before the chosen character def on_char_add(args): # --------------------------------------------------------------- # The line below makes sure that the code below will only run # when a document is active with your chosen language. # Change YOURLANGUAGENAME to the exact name of your User Defined # Language. # --------------------------------------------------------------- if notepad.getLanguageName(LANGTYPE.USER) == "udf - YOURLANGUAGENAME": # ----------------------------------------------------------- # Uncomment the line below, and run the script. # When typing text in a file with the chosen language above, # the "ch" number will show in the console. # Use that number to change the added_char value below, # this will change the character that opens the calltip. # ----------------------------------------------------------- # print(args) added_char = args["ch"] if ( added_char == 32 ): # Number 32 is the "space" character, change to whatever you want. pos = editor.getCurrentPos() - 1 search_word = editor.getTextRange( editor.wordStartPosition(pos, True), editor.wordEndPosition(pos, True) ) # Search for the the search_word information in the dictionary for keyword in data_dict["NotepadPlus"]["AutoComplete"]["KeyWord"]: if keyword.get("name") == search_word: nl = "\n" name_value = keyword.get("name") overload_values = keyword.get("Overload") retval_value = overload_values.get("retVal") descr_value = overload_values.get("descr") param_value = keyword.get("Overload")["Param"]["name"] retval_text = "RetVal: " + retval_value param_text = "Param: " + param_value # Create calltip from all retrieved text calltip = ( pad + nl + name_value + nl + pad + nl + retval_text + nl + pad + nl + descr_value + nl + pad + nl + param_text + nl + pad ) # Wrap the text for calltip calltip_wrap = nl.join( [ nl.join( textwrap.wrap( line, 70, break_long_words=False, replace_whitespace=False, ) ) for line in calltip.splitlines() if line.strip() != "" ] ) # Show the calltip editor.callTipShow(editor.getCurrentPos(), calltip_wrap) # Open console and show install message console.show() print("Calltip on any character installed, its safe to close this console.") # Scintilla callback notifications editor.callback(on_char_add, [SCINTILLANOTIFICATION.CHARADDED])
-
I had some free time and had another go at multiple overloads, but there seems to be a bug with the down arrow in the tooltip / and the alt+down shortcut combo when using PythonScript. Obviously there is nothing wrong with the standard implementation of this feature, only when creating a custom tooltip with PythonScript does this CTD happen.
I did a small test with the SCINTILLANOTIFICATION.CALLTIPCLICK and this was the result, position 0 is clicked anywhere but the arrows, position 1 is clicked on the up arrow and position 2 should be clicked on the down arrow… but this results in Notepad++ crashing to desktop.
-
@Khundian-Twitch ,
Just a note, and I’m not sure if this is relevant with what you’re doing with pythonscript, but the calltip functions are triggered by a delimiter insertion, meaning when you type the keyword, and then click a parens if it is the opening for a function, then the calltip pops up, and you have to use the mouse to click the buttons up or down.What you’re doing, may not make what I just mentioned relevant, since it sounds like you’re past my knowledge, but I thought I might mention in in case it is relevant.
-
@Khundian-Twitch said in Calltip on mouse-over from UDL xml file (Python):
I did a small test with the SCINTILLANOTIFICATION.CALLTIPCLICK and this was the result, position 0 is clicked anywhere but the arrows, position 1 is clicked on the up arrow and position 2 should be clicked on the down arrow… but this results in Notepad++ crashing to desktop.
Exits with
Exception Code: c0000094
which is a division by zero code. Seems the
position
key cannot return a value2
as it fails to get a value.Also a second error
Exception Code: c000041d
A STATUS_FATAL_USER_CALLBACK_EXCEPTION code.
This is what I tested with:
from Npp import console, editor, notepad, SCINTILLANOTIFICATION try: callback_registry except: callback_registry = [] calltip_wrap = ['\x01 one\n\x02 description', '\x01 two\n\x02 description'] if not editor.callTipActive(): editor.callTipShow(editor.getCurrentPos(), calltip_wrap[0]) def calltip_update(args): console.write(args) pos = editor.getCurrentPos() if editor.callTipActive(): if args['position'] == 2: editor.callTipCancel() editor.callTipShow(pos, calltip_wrap[0]) elif args['position'] == 1: editor.callTipCancel() editor.callTipShow(pos, calltip_wrap[1]) return True if 'calltip_update' not in callback_registry: callback_registry.append('calltip_update') editor.callback(calltip_update, [SCINTILLANOTIFICATION.CALLTIPCLICK])
-
@mpheath Thanks for taking the time to test, reply and clarify the issue.
I guess I’m out of luck. I wonder if it’s something with the PythonScript plugin, when I have some time I’m gonna test with the LuaScript plugin and see if the same happens when creating a calltip. -
I tested with the LuaScript plugin and exactly the same happens, I guess it has nothing to do with either Python or LUA plugin. I guess its a bug in Scintilla or Notepad++. I’ll post the LUA code I used to test below.
function showcalltip(ch) calltip = "\001 <Click> \002" pos = editor.CurrentPos editor:CallTipShow(pos, calltip) return false end function printclick(flag) print(flag) return false end print("Test script running.") npp.AddEventHandler("OnChar", showcalltip) npp.AddEventHandler("OnCallTipClick", printclick)
-
@Khundian-Twitch said in Calltip on mouse-over from UDL xml file (Python):
I guess its a bug in Scintilla or Notepad++
A crash is a pretty big deal; someone should open an official bug report on github.
-
@Alan-Kilborn said in Calltip on mouse-over from UDL xml file (Python):
@Khundian-Twitch said in Calltip on mouse-over from UDL xml file (Python):
I guess its a bug in Scintilla or Notepad++
A crash is a pretty big deal; someone should open an official bug report on github.
I agree, but I’m not sure if this qualifies as a bug in Notepad++?
The standard implementation of using the arrows to cycle through multiple overloads works fine. Its only when a user starts tinkering with script plugins and creating their own calltips that this crash will occur. -
I created a bug report on github, guess we’ll see if it qualifies as a bug. Link to report
-
@mpheath Seems it was something in the Notepad++ code, but solved very quickly by the guys on github. Without a doubt the debug info you provided had something to do with that, Thanks again! :)
-
@Khundian-Twitch Well done! I tested the artifact in PR #14667 that solves the crash issue and so now position
2
is possible for the down arrow of the calltip. -
I have finished the script, if anyone is interested I posted it in the Plugin development forum.
Thanks again to everyone who helped me out!