Page 4 of 11

Re: CodeQuickTester

Posted: 31 May 2015, 13:34
by geek
Whoops, looks like I broke the gist open button from the extension, fixed now. @BGM Check the original post, the greasemonkey script is in a spoiler tag about 2/3 the way down.

I've just updated the code tester as well.
  • Moved config to top of script
  • Added default file option to config (Defaults to ShellNew)
  • Made selected text length more responsive
  • Changed pastebin dropdown to combobox
  • Updated to new pastebin URL
  • Added A_AhkDir to the hashbang decoder

Re: CodeQuickTester

Posted: 01 Jun 2015, 22:55
by geek
I'm going to go ahead and push this out. Introducing Auto Indent, modified from @maestrith's amazing AHK Studio!
  • Added menu button for Auto Indent

Re: CodeQuickTester

Posted: 02 Jun 2015, 09:59
by BGM
You should add triple-click to select an entire line

Re: CodeQuickTester

Posted: 02 Jun 2015, 10:01
by maestrith
aww :) you called Studio amazing :)

Re: CodeQuickTester

Posted: 04 Jun 2015, 18:17
by geek
I just updated the code tester! This update brings the use of a RichEdit control. Also, I've added a hotkey for opening the help file. Kudos to @just_me for his help with the RE, and his wonderful RE class I used as a guide. Also thanks to @BGM for his feedback in the IRC.
  • Switched to using a RichEdit control
  • Triple click selects whole line
  • Added options for variable tab width, font, typeface, font color, bgcolor etc.
  • ^h to open help file

Re: CodeQuickTester

Posted: 10 Aug 2015, 16:56
by geek
What do you guys think about switching to a more OOP code base? Here's an unfinished example

Code: Select all

#SingleInstance, Off
#NoEnv
SetBatchLines, -1

Menu, Tray, Icon, %A_AhkPath%, 2
FileEncoding, UTF-8

MyTester := new CodeQuickTester()
return

class CodeQuickTester
{
	static Msftedit := DllCall("LoadLibrary", "Str", "Msftedit.dll")
	
	__New()
	{
		this.DefaultPath := "C:\Windows\ShellNew\Template.ahk"
		this.DefaultName := "GeekDude"
		this.DefaultDesc := ""
		this.FGColor := 0xCDEDED
		this.BGColor := 0x3F3F3F
		this.TabSize := 4
		this.Indent := "`t"
		this.TypeFace := "Consolas"
		this.Font := "s9 wBold"
		this.Title := "CodeQuickTester"
		
		this.Shell := ComObjCreate("WScript.Shell")
		
		; TODO: This makes the class never get garbage collected. Oops!
		Buttons := new this.MenuButtons(this)
		Menu := 
		( Join
		[
			["&File", [
				["&Save`tCtrl+S", Buttons.Save.Bind(Buttons)],
				["&Open`tCtrl+O", Buttons.Open.Bind(Buttons)],
				["&Fetch", Buttons.Fetch.Bind(Buttons)]
			]], ["&Tools", [
				["&Paste`tCtrl+P", Buttons.Paste.Bind(Buttons)],
				["Re&indent", Buttons.Indent.Bind(Buttons)],
				["Install", Buttons.Install.Bind(Buttons)],
				["&Help`tF1", Buttons.Help.Bind(Buttons)]
			]]
		]
		)
		
		Gui, New, +Resize +hWndhMainWindow
		this.hMainWindow := hMainWindow
		Gui, Menu, % this.CreateMenuBar(Menu)
		Gui, Margin, 5, 5
		
		Gui, Font, % this.Font, % this.TypeFace
		
		this.InitRichEdit()
		
		Gui, Font, s8 w400 q0, Microsoft Sans Serif
		Gui, Add, Button, hWndhRunButton, &Run
		RunFunc := this.RunButton.Bind(this) ; TODO: This makes the class never get garbage collected. Oops!
		GuiControl, +g, %hRunButton%, %RunFunc%
		this.hRunButton := hRunButton
		Gui, Add, StatusBar
		SB_SetParts(70, 70, 70)
		
		WinEvents.Register(this.hMainWindow, new this.Events(this))		
		Gui, Show, w640 h480, % this.Title
	}
	
	InitRichEdit()
	{
		Gui, Add, Custom, ClassRichEdit50W hWndhWnd +0x5031b1c4 +E0x20000
		this.hCodeEditor := hWnd
		
		; Set background color
		SendMessage, 0x443, 0, this.BGColor,, ahk_id %hWnd% ; EM_SETBKGNDCOLOR
		
		; Set FG color
		VarSetCapacity(CharFormat, 116, 0)
		NumPut(116, CharFormat, 0, "UInt") ; cbSize := sizeOf(CHARFORMAT2)
		NumPut(0x40000000, CharFormat, 4, "UInt") ; dwMask := CFM_COLOR
		NumPut(this.FGColor, CharFormat, 20, "UInt") ; crTextColor := 0xBBGGRR
		SendMessage, 0x444, 0, &CharFormat,, ahk_id %hWnd% ; EM_SETCHARFORMAT
		
		; Set tab size to 4
		VarSetCapacity(TabStops, 4, 0), NumPut(this.TabSize*4, TabStops, "UInt")
		SendMessage, 0x0CB, 1, &TabStops,, ahk_id %hWnd% ; EM_SETTABSTOPS
		
		; Change text limit from 32,767 to max
		SendMessage, 0x435, 0, -1,, ahk_id %hWnd% ; EM_EXLIMITTEXT
		
		; Disable inconsistent formatting
		SendMessage, 0x4CC, 1, 1,, ahk_id %hWnd% ; EM_SETEDITSTYLE SES_EMULATESYSEDIT
	}
	
	CreateMenuBar(Menu)
	{
		static MenuName := 0
		MyMenuName := "CQT_" MenuName, MenuName++
		for each, Item in Menu
		{
			Ref := Item[2]
			if IsObject(Ref) && Ref._NewEnum()
				Ref := ":" this.CreateMenuBar(Ref)
			Menu, %MyMenuName%, Add, % Item[1], %Ref%
		}
		return MyMenuName
	}
	
	RunButton()
	{
		if (this.Exec.Status == 0) ; Running
			this.Exec.Terminate() ; CheckIfRunning updates the GUI
		else ; Not running or doesn't exist
		{
			GuiControlGet, CodeEditor,, % this.hCodeEditor
;			GuiControlGet, Params, Params:
			this.Exec := ExecScript(CodeEditor, "", DeHashBang(CodeEditor)) ; TODO: Implement Params
			GuiControl,, % this.hRunButton, &Kill
			
			BoundFunc := this.CheckIfRunning.Bind(this, Context := {})
			Context.BoundFunc := BoundFunc
			SetTimer, %BoundFunc%, 100
		}
	}
	
	CheckIfRunning(Context)
	{
		if (this.Exec.Status == 1)
		{
			BoundFunc := Context.BoundFunc
			SetTimer, %BoundFunc%, Delete
			GuiControl,, % this.hRunButton, &Run ; TODO: Make sure I don't have to specify default gui
		}
	}
	
	class MenuButtons
	{
		__New(Parent)
		{
			this.Parent := Parent
		}
		
		Save()
		{
			Gui, +OwnDialogs
			FileSelectFile, FilePath, S2
			if ErrorLevel
				return
			GuiControlGet, CodeEditor,, % this.Parent.hCodeEditor
			
			; TODO: Confirm before overwrite
			FileOpen(FilePath, "w").Write(CodeEditor)
		}
		
		Open()
		{
			; TODO
		}
		
		Fetch()
		{
			; TODO
		}
		
		Paste()
		{
			; TODO
		}
		
		Indent()
		{
			; TODO
		}
		
		Help()
		{
			Run, %A_AhkPath%\..\AutoHotkey.chm
		}
		
		Install()
		{
			; TODO
		}
	}
	
	class Events
	{
		__New(Parent)
		{
			this.Parent := Parent
		}
		
		Size()
		{
			ToolTip, hi
			GuiControl, Move, % this.Parent.hCodeEditor, % "x" 5 "y" 5 "w" A_GuiWidth-10 "h" A_GuiHeight-60
			ButtonWidth := (A_GuiWidth-10)
			GuiControl, Move, % this.Parent.hRunButton, % "x" 5 "y" A_GuiHeight-50 "w" ButtonWidth "h" 22
		}
		
		Close()
		{
			; TODO: Allow multiple instances?
			ExitApp
		}
	}
}

; TODO: Decide if I should keep a separate class for
; event dispatching or if I should handle it all inline.
class WinEvents ; static class
{
	static Table := {}
	
	Register(hWnd, Class)
	{
		Gui, +LabelWinEvents.
		this.Table[hWnd] := Class
	}
	
	Unregister(hWnd)
	{
		this.Table.Delete(hWnd)
	}
	
	Dispatch(hWnd, Type)
	{
		Class := this.Table[hWnd]
		
		; TODO: Decide if it should use a prefix for the method name
		Class[Type].Call(Class)
	}
	
	; These *CANNOT* be added dynamically or handled dynamically via __Call
	Close()
	{
		WinEvents.Dispatch(this, "Close")
	}
	
	Escape()
	{
		WinEvents.Dispatch(this, "Escape")
	}
	
	Size()
	{
		WinEvents.Dispatch(this, "Size")
	}
	
	ContextMenu()
	{
		WinEvents.Dispatch(this, "ContextMenu")
	}
	
	DropFiles()
	{
		WinEvents.Dispatch(this, "DropFiles")
	}
}

; Modified from https://github.com/cocobelgica/AutoHotkey-Util/blob/master/ExecScript.ahk
ExecScript(Script, Params="", AhkPath="")
{
	Name := "AHK_CQT_" A_TickCount
	Pipe := []
	Loop, 2
	{
		Pipe[A_Index] := DllCall("CreateNamedPipe"
		, "Str", "\\.\pipe\" name
		, "UInt", 2, "UInt", 0
		, "UInt", 255, "UInt", 0
		, "UInt", 0, "UPtr", 0
		, "UPtr", 0, "UPtr")
	}
	if !FileExist(AhkPath)
		AhkPath := A_AhkPath
	Call = "%AhkPath%" /CP65001 "\\.\pipe\%Name%"
	Shell := ComObjCreate("WScript.Shell")
	Exec := Shell.Exec(Call " " Params)
	DllCall("ConnectNamedPipe", "UPtr", Pipe[1], "UPtr", 0)
	DllCall("CloseHandle", "UPtr", Pipe[1])
	DllCall("ConnectNamedPipe", "UPtr", Pipe[2], "UPtr", 0)
	FileOpen(Pipe[2], "h", "UTF-8").Write(Script)
	DllCall("CloseHandle", "UPtr", Pipe[2])
	return Exec
}

DeHashBang(Script)
{
	AhkPath := A_AhkPath
	if RegExMatch(Script, "`a)^\s*`;#!\s*(.+)", Match)
	{
		AhkPath := Trim(Match1)
		Vars := {"%A_ScriptDir%": A_WorkingDir
		, "%A_WorkingDir%": A_WorkingDir
		, "%A_AppData%": A_AppData
		, "%A_AppDataCommon%": A_AppDataCommon
		, "%A_LineFile%": A_ScriptFullPath
		, "%A_AhkPath%": A_AhkPath
		, "%A_AhkDir%": A_AhkPath "\.."}
		for SearchText, Replacement in Vars
			StringReplace, AhkPath, AhkPath, %SearchText%, %Replacement%, All
	}
	return AhkPath
}

Re: CodeQuickTester

Posted: 10 Aug 2015, 23:46
by dd900
Looks good. I just tested this with CodeQuickTester then I used the new instance to load another instance of CodeQuickTester.

CodeQuickTesterCeption

Re: CodeQuickTester

Posted: 11 Aug 2015, 08:58
by geek
What effect do you think this new approach has on code readability?

Re: CodeQuickTester

Posted: 11 Aug 2015, 10:43
by joedf
dd900 wrote:Looks good. I just tested this with CodeQuickTester then I used the new instance to load another instance of CodeQuickTester.

CodeQuickTesterCeption
:D

Re: CodeQuickTester

Posted: 11 Aug 2015, 11:22
by dd900
GeekDude wrote:What effect do you think this new approach has on code readability?
I think that would depend on the user. I myself find it easier to read the newer version, but that's only because I am familiar with how classes work in ahk (thank you lexikos). Someone with no experience using objects or classes in ahk or any other language might not understand what is going on in the code.

I say continue with the new OOP aproach

Re: CodeQuickTester

Posted: 11 Aug 2015, 11:45
by geek
A fun side effect is that you can create multiple instances of the code editor from one script. That could make it easier for me to add a "open new instance" button that works while the script is being run dynamically.

Re: CodeQuickTester

Posted: 11 Aug 2015, 12:51
by joedf
+1

Re: CodeQuickTester

Posted: 17 Aug 2015, 11:18
by geek
Run this, and click the run button a few times. Works fine, right? Click the edit box, then click the run button a few more times. It gets stuck on "Kill". Now kill the script, and uncomment the two lines in the UpdateStatusBar method, and try again. Everything works fine. My question is why does that fix a seemingly unrelated problem? I'm baffled.

Code: Select all

#NoEnv
MyTester := new CodeQuickTester()

class CodeQuickTester
{
	__New()
	{
		this.Bound := []
		this.Bound.RunButton := this.RunButton.Bind(this)
		this.Bound.OnMessage := this.OnMessage.Bind(this)
		this.Bound.UpdateStatusBar := this.UpdateStatusBar.Bind(this)
		this.Bound.CheckIfRunning := this.CheckIfRunning.Bind(this)
		
		Gui, New, +Resize +hWndhMainWindow
		this.hMainWindow := hMainWindow
		
		Gui, Add, Edit, hWndhCodeEditor
		this.hCodeEditor := hCodeEditor
		
		Gui, Add, Button, hWndhRunButton, &Run
		this.hRunButton := hRunButton
		
		BoundFunc := this.Bound.RunButton
		GuiControl, +g, %hRunButton%, %BoundFunc%
		
		OnMessage(0x201, this.Bound.OnMessage)
		Gui, Show
	}
	
	RunButton()
	{
		GuiControl,, % this.hRunButton, &Kill
		
		BoundFunc := this.Bound.CheckIfRunning
		SetTimer, %BoundFunc%, 100
	}
	
	CheckIfRunning()
	{
		BoundFunc := this.Bound.CheckIfRunning
		SetTimer, %BoundFunc%, Delete
		GuiControl,, % this.hRunButton, &Run ; TODO: Make sure I don't have to specify default GUI
	}
	
	OnMessage(wParam, lParam, Msg, hWnd)
	{
		if (hWnd == this.hCodeEditor)
		{
			; Call BoundFunc after we return and the key press propagates downwards into the edit
			BoundFunc := this.Bound.UpdateStatusBar
			SetTimer, %BoundFunc%, -0
		}
	}
	
	UpdateStatusBar()
	{
		; BoundFunc := this.Bound.UpdateStatusBar
		; SetTimer, %BoundFunc%, Delete
		return
	}
}

Re: CodeQuickTester

Posted: 31 Aug 2015, 12:29
by geek
I'm moving to a real repo on GitHub! https://github.com/G33kDude/CodeQuickTester/tree/dev
Single-file versions can be found in the main branch.

Re: CodeQuickTester

Posted: 01 Sep 2015, 04:12
by cyruz
Nice, the app deserves a dedicated repo :D

Re: CodeQuickTester

Posted: 10 Sep 2015, 13:20
by TLM
FR: 1 click code commenting plz :D

Re: CodeQuickTester

Posted: 05 Oct 2015, 15:12
by geek
The main post has been updated with a link to the latest version in the github repo.

Re: CodeQuickTester

Posted: 09 Nov 2015, 08:17
by geek
UserScript updated to v0.4.1 (namespace update for new forum domain)

Re: CodeQuickTester

Posted: 04 Aug 2017, 10:18
by geek
Sneak peek

Image

Re: CodeQuickTester

Posted: 04 Aug 2017, 10:35
by maestrith
Scintilla or RichEdit?