Highlight words in MaxScript Editor


#21

Thank you for your creative discussion. I successfully achieved the desired effect

edit your MXS_EditorUser.properties, check and add style, I used a dark theme. This color may not be suitable for you

  • Keywords14 - structure and FPS properties
  • style.MAXScript.25=fore:#FFFF00,back:#3A52D8

This is my modified code. After execution, you can double-click the keyword to highlight it automatically.

(
	local owner
	struct mxse_struct
	(
		doc = "",
		keywords = #("about","and","animate","as","at","attributes","by","case","catch","collect","continue","coordsys","do","else","exit","fn","for","from","function","global","if","in","local","macroscript","mapped","max","not","of","off","on","or","parameters","persistent","plugin","rcmenu","return","rollout","set","struct","then","throw","to","tool","try","undo","utility","when","where","while","with"),
		ignore = keywords + #("(", ")", "[", "]", "{", "}", "#", "$", "%", ".", ":", "\"", "\'", "_", "==", "`", "=", "+", "-", ">", "<", "*", "/", "\\", "@", "^", "&", ";", ",", ":"), --排除
		results = #(),
		editorHandle     = (dotNetClass "Autodesk.Max.GlobalInterface").Instance.TheMxsEditorInterface.EditorGetMainHWND,
		currentlyOpenTab = (dotNetClass "Autodesk.Max.GlobalInterface").Instance.TheMxsEditorInterface.EditorGetEditHWND,
		
		fn GetDocument =
		(	
			for c in (windows.getchildrenhwnd editorHandle) where c[1] == currentlyOpenTab do doc = c[5]
-- 			format "doc length: %\n" doc.count
			
			if doc.count != (windows.sendmessage currentlyOpenTab (SCI_GETLENGTH = 2006) 0 0) do
			(
-- 				format "getting doc differently...\n" 
				
				local marshal = dotnetclass "System.Runtime.InteropServices.Marshal"
				str = ""
				try (
					len = windows.sendmessage currentlyOpenTab 0xE 0 0
					lParam = marshal.AllocHGlobal (marshal.SystemDefaultCharSize*(len+1))
					windows.sendmessage currentlyOpenTab 0xD (len+1) lParam 
						
					ptr = dotnetobject "System.IntPtr" lParam
					str = marshal.PtrToStringAuto ptr
					marshal.FreeHGlobal ptr
					
				) catch ()
				doc = str
			)
			
		),
		
		fn ResetDocumentStyle = 
		(
			windows.sendmessage currentlyOpenTab (SCI_COLOURISE = 4003) 0 -1
-- 			windows.sendMessage editorHandle (WM_COMMAND = 0x111) 1401 0 -- reset styling				
		),
		
		fn Colorize pos len style:25 = 
		(
			windows.sendMessage currentlyOpenTab (SCI_STARTSTYLING = 2032) pos -1
			windows.sendMessage currentlyOpenTab (SCI_SETSTYLING = 2033) len style
		),
	
		fn HighlightText txt reload:true =
		(
			if reload do GetDocument()
			
			local ss = (tolower owner.doc) as stringstream
			seek ss 0
			
			results = #()
			
			local query = tolower txt
			while undefined != skiptostring ss query do
			(
				append results (filePos ss - query.Count)
			)
					
			if results.count > 0 do ResetDocumentStyle()
			
			for res in results do owner.Colorize res txt.count
				
-- 			format "results: %\n" results
			
			if results.count > 0 do 
			(
				seek ss (amax results)
				try
				(
					skipToNextLine ss -- skipping a few lines otherwise the last result isn't highlighted
					skipToNextLine ss
				)catch()
				
				owner.Colorize (filePos ss) 0 style:0 -- some magic to fix the last result
			)
		),
		
		fn HighlightSelection reload:true reset:false =
		(
			local start = 1 + (windows.sendMessage currentlyOpenTab (SCI_GETSELECTIONSTART = 2143) 0 0)
			local end   = 1 + (windows.sendMessage currentlyOpenTab (SCI_GETSELECTIONEND = 2145)   0 0)
			
			if reset do
			(				
				windows.sendMessage currentlyOpenTab (SCI_SETSELECTIONSTART = 2142) (end - 1) 0
				windows.sendMessage currentlyOpenTab (SCI_SETSELECTIONEND = 2144) (end - 1) 0			
			)
			
			if reload do GetDocument()
			
			local query = substring doc start (end - start)

			if query.count > 0 then
			(
				query = (dotNetObject "System.String" query).Trim()
				query = (dotNetObject "System.String" query).Replace "\n" ""
				query = (dotNetObject "System.String" query).Replace "\t" ""
				query = (dotNetObject "System.String" query).Replace "\r" ""
				if findItem ignore query == 0 do HighlightText query reload:false 
			)else
			(
				ResetDocumentStyle()
			)
		),
		
		fn GoToResult index:1 = if results.count > 0 do
		(
			if index > results.count do index = 1
				
			windows.sendMessage currentlyOpenTab (SCI_GOTOPOS = 2025) results[index] 0			
		),
		
		fn IsMaxscriptLexer = 
		(
			(windows.sendmessage currentlyOpenTab (SCI_GETLEXER = 4002) 0 0) == 81	
		),
		
		on create do owner = this
	)
	
	global mxse = mxse_struct()
	ok
)

global mxse_listener
(
	local owner
	struct mxse_listener_struct
	(
		dll,

		fn LParamToPoint lparam = 
		(
			[ bit.and lparam 0xFFFF, bit.and (bit.shift lparam -16) 0xFFFF ]			
		),
		
		fn OnMessage ev = 
		(
			::mxse.HighlightSelection()
		),
		
		fn Start hwnd =
		(
			dll.assignHandle (dotNetObject "System.IntPtr" hwnd)
			dotnet.addEventHandler dll "MessageEvent" OnMessage
		),
		
		fn Stop = 
		(
			dll.releaseHandle()
			dotnet.removeEventHandlers dll "MessageEvent"	
		),
		
		on create do
		(
			owner = this
			local source = "
			using System;
			using System.Windows.Forms;
			class MessageSnooper : NativeWindow
			{
				public System.Collections.Generic.HashSet<int> allowed_messages = new System.Collections.Generic.HashSet<int>();
				public delegate void MessageHandler(object msg);
				public event MessageHandler MessageEvent;
				protected override void WndProc(ref Message m)
				{
					base.WndProc(ref m);
					if (MessageEvent != null && allowed_messages.Contains( m.Msg )) MessageEvent((object)m);
				}
			}"

			csharpProvider = dotnetobject "Microsoft.CSharp.CSharpCodeProvider"
			compilerParams = dotnetobject "System.CodeDom.Compiler.CompilerParameters"
			compilerParams.ReferencedAssemblies.AddRange #("system.dll", "system.windows.forms.dll", "system.core.dll");
			compilerParams.GenerateInMemory = on
			compilerResults = csharpProvider.CompileAssemblyFromSource compilerParams #(source)

			if (compilerResults.Errors.Count > 0 ) then
			(
				local errs = stringstream ""
				for i = 0 to (compilerResults.Errors.Count-1) do
				(
					local err = compilerResults.Errors.Item[i]
					format "Error:% Line:% Column:% %\n" err.ErrorNumber err.Line err.Column err.ErrorText to:errs
				)
				format "%\n" errs
				undefined
			)
			else dll = compilerResults.CompiledAssembly.CreateInstance "MessageSnooper"
			
		)
		
	)
	
	if ::mxse_listener != undefined do ( try ( ::mxse_listener.Stop(); mxse_listener = undefined ) catch() )

	::mxse_listener = mxse_listener_struct()
	::mxse_listener.Start (dotNetClass "Autodesk.Max.GlobalInterface").Instance.TheMxsEditorInterface.EditorGetEditHWND
	
	
	::mxse_listener.dll.allowed_messages.Add 0x202  --侦听鼠标左键单击 WM_LBUTTONUP  0x202 WM_LBUTTONDOWN  0x201
	
	format "started...\n" 
)


#22

The next version of 3ds Max (2024.x):

Maxscript editor now supports highlighting of all instances of selected text.