2.12.1 released

Posted - 01 May 2016

A new bug fix release is out, mostly minor fixes which you can see in the changelog. There is one new feature though that I am rather excited about; There are new Lua bindings for scripts thanks to @mniip. If you are a scripter I’ll go more into detail on what makes this great…

Lua

Just some quick background information: the plugin supports lua[jit] 5.1-5.3, is shipped on all platforms, and the documentation can be found here.

The first thing that really stands out when switching from Python scripts to Lua ones is the resource usage. I have around 10 scripts loaded at any given time and the python plugin alone would use around 60MB of ram, when I rewrote every script in Lua that number decreased to about 4MB. On top of that luajit is an extremely fast interpreter though scripts are rarely CPU bound.

Another useful feature is that Lua is extremely portable, this means that Windows users do not need to deal with the hassle of downloading a giant Python installer that ends up broken, requires rebooting, or is incompatable with a script. The Windows installer will include all of Lua itself which is effectively a 1MB single binary and will be installed by default so scripters can be confident users have it.

Lastly and my favorite feature is the ability to use a library called lgi. GObject-Introspection is a technology that allows information about C libraries to be used externally (usually from other languages). This means that scripts can integrate with the same libraries HexChat uses itself such as GLib and Gtk. This library is small enough that we will be bundling it on Windows which means for the first time all Windows users can have scripts that can easily modify the UI or integrate with the mainloop.

Here are some basic examples that should give you an idea of more advanced things you can do with this ability:

local lgi = require ( 'lgi' ) local GLib = lgi . require ( 'GLib' ) local Gio = lgi . require ( 'Gio' ) hexchat . register ( 'FileTest' , '1' , 'Opens a file async' ) --[[ A common problem in scripts is that they have to do blocking IO operations and in a graphical application like HexChat this means locking up the client. To avoid this GLib provides many asynchronous APIs that use threads and the mainloop to avoid blocking. This is just an example of opening a large file without blocking. ]] -- hexchat . hook_command ( 'readfile' , function ( word , word_eol ) if # word < 2 then print ( 'Need a file name' ) return hexchat . EAT_ALL elseif not GLib . path_is_absolute ( word [ 2 ]) then print ( 'Need an absolute path' ) return hexchat . EAT_ALL end local file = Gio . File . new_for_path ( word [ 2 ]) local original_context = hexchat . props . context -- This starts another thread and calls the function when it is finished file : load_contents_async ( nil , function ( file , result ) local contents , etag , err = file : load_contents_finish ( result ) -- We need to manually reset the context as it may have changed if not original_context : set () then hexchat . find_context (): set () -- front print ( 'Original context lost' ) end if err then print ( 'Error reading file: ' .. tostring ( err )) else print ( 'File contained: ' .. # contents .. ' bytes' ) end end ) return hexchat . EAT_ALL end )

local lgi = require ( 'lgi' ) local Gtk = lgi . require ( 'Gtk' , '2.0' ) hexchat . register ( 'WinTile' , '1' , 'Tile the window left/right' ) --[[ HexChat being a graphical application many times you want scripts to modify the UI, this is just a simple script that takes a reference to the main window and modifies it in a simple way (moving and resizing). In practice you can do any operation you would like including spawning new windows and modifying widgets. ]] -- hexchat . hook_command ( 'tile' , function ( word , word_eol ) if # word < 2 then print ( 'Need side, left, right, or reset' ) return hexchat . EAT_ALL end local side = word [ 2 ]: lower () local window = Gtk . Window ( hexchat . get_info ( 'gtkwin_ptr' )) if side == 'reset' then local width , height = hexchat . prefs [ 'gui_win_width' ], hexchat . prefs [ 'gui_win_height' ] local x , y = hexchat . prefs [ 'gui_win_left' ], hexchat . prefs [ 'gui_win_top' ] window : resize ( width , height ) window : move ( x , y ) hexchat . command ( 'set -quiet gui_win_save on' ) elseif side == 'left' or side == 'right' then local screen = window : get_screen () local width , height = screen : get_width (), screen : get_height () hexchat . command ( 'set -quiet gui_win_save off' ) -- We don't want to save the temporary size window : resize ( width / 2 , height ) if side == 'left' then window : move ( 0 , 0 ) else window : move ( width / 2 , 0 ) end else print ( 'Invalid side. Need left, right, or reset' ) end return hexchat . EAT_ALL end )

Related Posts