Using Lua scripts (Part 13): Useful functions and code - brndnmtthws/conky GitHub Wiki

xiii: Useful functions and code

In general I like to work out my own functions and write them myself, but sometimes its just easier to use existing functions that other people have made,

Here are some examples of function that I use regularly in scripts.

Split string function

function string:split (delimiter)
	local result = {}
	local from = 1
	local delim_from, delim_to = string.find (self, delimiter, from)
	while delim_from do
		table.insert (result, string.sub (self, from , delim_from - 1))
		from = delim_to + 1
		delim_from, delim_to = string.find (self, delimiter, from)
	end
	table.insert ( result, string.sub (self, from))
	return result
end

This function takes a string and splits it up at a given delimiter then puts all the pieces into a table.

You put this function into your Lua script (either above the main function, or below (which will work due to the way Conky and Lua work together)).

In the main function you use it like this:

text_string = "this is some text I want to split up into individual words"
split_table = string.split (text_string," ")

So, text_string contains the stuff we want to split up. split_table is the name of the table that we will be putting the pieces into. string.split () is how we call the function.

This looks a little bit different from how we have called functions in the past: the function itself is set up a little differently too, but it works!

Then inside the () we send the function the information it needs.

First the string we want to split up (text_string, " ") then the delimiter, the place at which we want to split the string. In this case I have set a single space (text_string, " ").

You can use anything you like to split the string up.

So what you get is a table called split_table which looks like this.

split_table = {
	"this",
	"is",
	"some",
	"text",
	"i",
	"want",
	"to",
	"split",
	"up",
	"into",
	"individual",
	"words",
}

So we can access each entry in the table individually, for example:

print (split_table[1]) --> "this"
print (split_table[6]) --> "want"

This has a great number of applications.

Color conversion function

Lua uses RGBA values to set colors like so: cairo_set_source_rgba (cr, 1, 1, 1, 1).

Each number in the () brackets is between 0 and 1 so in this case 1, 1, 1, 1 will give me fully opaque white.

BUT if you are more familiar with setting colors with hexidecimal values then you need to convert the hexidecimal values to RGBA values.

You can do it using this function:

function color_convert (c, a)
	return ((c / 0x10000) % 0x100) / 255, ((c / 0x100) % 0x100) / 255,
			(c % 0x100) / 255, a
end

There are several variations of this function floating around. As with all functions, put it in the script outside of the main function, either above or below. Just remember that it is only due to the way that Conky and Lua work together that you can have function below the main function. If you ever write a standalone Lua script (I do this as an alternative to bash scripts) then you HAVE to define your functions BEFORE they are used, ie ABOVE.

There are a few different ways you can use this:

hex_color = 0xffffff
alpha = 1
red, green, blue, alpha = color_convert (hex_color, alpha)
cairo_set_source_rgba (cr, red, green, blue, alpha)

Sometimes breaking code up into steps like above can be helpful.

NOTE on red, green, blue, alpha = color_convert (hex_color, alpha). Lua has the ability to return multiple values from the same function. In this case the colorconvert funtion is returning 4 values, so we need to set 4 strings to accept those values.

When we do this we get the string set in the same order that they are returned:

For example, you have in your function:

function number ()
	return 1, 2, 3, 4
end

And you call it like this:

one, two, three, four = numbers ()
print (one) --> 1
print (three) --> 3

two, three, one, four = numbers ()
print (one) --> 3
print (three) -->2

HOWEVER, you could do the same thing in fewer lines like this: cairo_set_source_rgba (cr, color_convert (0xffffff, 1)). In this case the returned vales are being fed directly to the color setting function.

Image display function

function image (im)--
	x = nil
	x = (im.x or 0)
	y = nil
	y = (im.y or 0)
	w = nil
	w = (im.w or 0)
	h = nil
	h = (im.h or 0)
	file = nil
	file = tostring (im.file)
	if file == nil then print ("set image file") end
	---------------------------------------------
	local show = imlib_load_image (file)

	if show == nil then return end
	imlib_context_set_image (show)
	if tonumber (w) == 0 then
		width = imlib_image_get_width ()
	else
		width = tonumber (w)
	end

	if tonumber (h) == 0 then
		height = imlib_image_get_height ()
	else
		height = tonumber (h)
	end

	imlib_context_set_image (show) 
	local scaled = imlib_create_cropped_scaled_image (0, 0,
			imlib_image_get_width (), imlib_image_get_height (), width, height) 
	imlib_free_image ()
	imlib_context_set_image (scaled)
	imlib_render_image_on_drawable (x, y)
	imlib_free_image ()
	show = nil
end

You use it like this: image ({x = 100, y = 100, h = 50, w = 50, file = "/home/username/cute_puppy.png"}).

when I was writing this function I wanted the input part to be as streamlined as possible, and I also wanted the ability to set default values so that you dont have to enter every setting every time you wanted to display an image.

To achieve this, you need to set and send a TABLE, and this is what I am doing by using the curly brackets {} inside the curved brackets ().

This also means that you DONT have to enter the values in any particular order either, ie image ({x = 100, y = 100, h = 50, w = 50, file = "/home/username/cute_puppy.png"}) does the same thing as: image ({file = "/home/username/cute_puppy.png",h = 50, x = 100, y = 100, w = 50}).

NOTE, the function contains these lines:

function image (im)
x = nil
x = (im.x or 0)
y = nil
y = (im.y or 0)
w = nil
w = (im.w or 0)
h = nil
h = (im.h or 0)
file = nil
file = tostring (im.file)

So everything you send the function is received by the function and put as separate entries in a table called "im". If we sent the info as described above and were then to look in the table "im" we would see this:

im = {
	x = 100,
	y = 100,
	h = 50,
	w = 50,
	file = "/home/username/cute_puppy.png"
}

So im is a dictionary-type table and we can access dictionary type tables in a couple of ways. In this case I am accessing the info using this method:

table_name.entry_in_table.

So to get the vale of x that we set in the main function when we called the function:

x_value = im.x
print (x_value) --> 100

Also note that i am doing this:

x = nil
x = (im.x or 0)

Setting x = nil is just a kind of maintenance line to catch and remove any other values of x that might be floating around in Lua space.

THEN (and this is a handy trick i picked up recently), x = (im.x or 0).

Which does the following ...

  • Checks the table "im" for a value for x.
  • If the table has an x value set in it then, set a string within the function called "x" that equals the value of x in table "im".
  • If there is NOT an entry for x in table "im", then im.x will return nil and if this is the case then x is set to 0.

This is where the defaults can be used; so when I call the function, say I want my image to be set to coordinates 0, 0 (I have the same lines for y as for x in the function) then I wouldn't need to enter a value for x.

image ({h = 50, w = 50, file = "/home/username/cute_puppy.png"}).

I sey the table to the function, the table gets read, there is no values for x or y so the script sets x both to 0.

Text output

I also wanted to streamline the output of text onto the Conky display

function out (tx)--
	c = nil
	c = (tx.c or 0xffffff)
	a = nil
	a = (tx.a or 1)
	f = nil
	f = (tx.f or "mono")
	fs = nil
	fs = (tx.fs or 12)
	x = nil
	x = (tx.x or 0)
	y = nil
	y = (tx.y or 0)
	txt = nil
	txt = (tx.txt or "set txt")

	local function col (c, a)
		return ((c / 0x10000) % 0x100) / 255,((c / 0x100) % 0x100) / 255,
				(c % 0x100) / 255, a
	end

	cairo_select_font_face (cr, f, CAIRO_FONT_SLANT_NORMAL,
			CAIRO_FONT_WEIGHT_NORMAL);
	cairo_set_font_size (cr, fs)
	cairo_set_source_rgba (cr, col (c, a))
	cairo_move_to (cr, x, y)
	cairo_show_text (cr, txt)
	cairo_stroke (cr)
end

Called like this in the main function: out ({x = 10, y = 10, c = 0xffffff, a = 1, f = "mono",fs = 12, txt = "hello world"}).

It works in a very similar way to the image function you only need to set those values that are different from the defaults.

NOTE: I am using the color conversion function (I called it "col" for brevity) that I described earlier in the out () function. However, I am using it as a local function, a function that is only available to the function which contains it. I put in the color conversion function as a local function in the out () function so that it would always be there and I wouldn't have to remember to put in 2 separate function every time I wanted to use out ().

Think of it like a dependency out () requires the ability to use the col () function. I could put the col function as a separate function in the script and use it that way BUT if I were to forget to put the col function in then I would get errors.

OK, thats it for this section.