SEARCH

Enter your search query in the box above ^, or use the forum search tool.

You are not logged in.

#51 2012-03-03 16:42:30

mrpeachy
20% cooler
From: The Everfree Forest
Registered: 2009-11-08
Posts: 3,460

Re: HOW TO : using lua scripts in conky

as long as all the main functions are named differently

function conky_something1()
--stuff
end--of function something1

function conky_something2()
--stuff
end--of function something2

function conky_something3()
--stuff
end--of function something3

you can stick them all into the same script and then on conky you can load up the one script and call each function below TEXT

lua_load path/to/megascript.lua

TEXT
${lua something1}${lua something2}${lua something2}

however, with some scripts that have complex multiple functions this method of combining scripts may not be the best way to go about it.

you can load up as many lua scripts as you want above text

lua_load script1.lua
lua_load script2.lua
lua_load script3.lua

TEXT

then, again as long as each of the main functions in the scripts is different then you can use the functions after TEXT

TEXT
${lua scritp1function}${lua scritp2function}${lua scritp3function}

another method is described here
http://u-scripts.blogspot.com/2011/02/h … conky.html

you have your scripts separate but set up in a "control" script that uses "package.path" and "require" commands

with just the single "control" script you then run your script and function above text

lua_load control.lua
lua_draw_hook_pre controlfunction

TEXT

but with this method and "require" you dont get "on the fly" changes to your output when you edit the various lua files

there are other ways too
like in v9000.lua

the template script "weather_script.lua" is loaded in the conkyrc
the display function in "weather_script.lua" set up as "global" function (thats what the _G means):

_G.weather_script = function()

this function is the accessible within the v9000.lua script

this way you get edits to the global functions showing up when you save.

v9000.lua also uses the "package.path" and "require" method to load the config file

Last edited by mrpeachy (2012-03-03 16:56:25)

Offline

Help fund CrunchBang, donate to the project!

#52 2012-03-03 19:03:03

Sector11
77345 ¡#
From: SR11 Cockpit
Registered: 2010-05-05
Posts: 11,433
Website

Re: HOW TO : using lua scripts in conky

@ mrpeachy

Well right now they are as complicated as trying to read Martian, my apologies to any Martian's in the house, since each script shows multiple samples of:

text, graphs, rings, clocks, boxes et al ...

So I want to use 'one' from each, maybe two' from a couple, but to determine what is needed after the function stuff is a nightmare, I'll leave all of that in, and just comment out what I do NOT want.

The LUA scripts look like this:

~/Conky/LUA/bargraph.lua
function conky_main_bars

~/Conky/LUA/rings2.lua
function conky_main_rings

~/Conky/LUA/text.lua
function conky_draw_text

~/Conky/LUA/clock.lua
function clock_widget

~/Conky/LUA/box.lua
function conky_main_box

So you are saying that I could do something like this which seems easiest for me, since I am LUA illiterate:

Option 1:

lua_load ~/Conky/LUA/bargraph.lua
lua_load ~/Conky/LUA/rings2.lua
lua_load ~/Conky/LUA/text.lua
lua_load ~/Conky/LUA/clock.lua
lua_load ~/Conky/LUA/box.lua

TEXT
${lua bargraph.lua conky_main_bars}\
${lua rings2.lua conky_main_rings}\
${lua text.lua conky_draw_text}\
${lua clock.lua clock_widget}\
${lua box.lua conky_main_box}\
normal conky stuff here

or Option 2: this is what I think you were saying

lua_load ~/Conky/LUA/bargraph.lua
lua_load ~/Conky/LUA/rings2.lua
lua_load ~/Conky/LUA/text.lua
lua_load ~/Conky/LUA/clock.lua
lua_load ~/Conky/LUA/box.lua

TEXT
${lua conky_main_bars}\
${lua conky_main_rings}\
${lua conky_draw_text}\
${lua clock_widget}\
${lua conky_main_box}\
normal conky stuff here

I appreciate what you said about v9000.  It's got to be one of the slickest LUA scripts going with the 'template' aspect.  But that LUA is way beyond my intellectual-grade (think government spy/NYC Cop movies: pay-grade)

They are wlourf's scripts and I'll check out that link later ... it too seems like Martian to me.


#! Forum Moderator | To #! or not to #!?  That is the question!
#! Conky = 16 Threads & the Conky Archives | Conky PitStop | OHCG'er
StartPage -  protect your privacy   |   BBQ Linux

Online

#53 2012-03-03 21:46:17

mrpeachy
20% cooler
From: The Everfree Forest
Registered: 2009-11-08
Posts: 3,460

Re: HOW TO : using lua scripts in conky

the second example in your post

if you would otherwise do this in conkyrc

lua_load script.lua
lua_draw_hook_pre mainfunction

TEXT


because in "script.lua" you have this

function conky_mainfunction()
--stuff
end--of main function

you could do this

lua_load script.lua

TEXT

${lua mainfunction}

the ${lua} function automatically puts "conky_" in front of the function name you set

Last edited by mrpeachy (2012-03-03 21:47:33)

Offline

#54 2012-03-04 02:50:37

Sector11
77345 ¡#
From: SR11 Cockpit
Registered: 2010-05-05
Posts: 11,433
Website

Re: HOW TO : using lua scripts in conky

mrpeachy wrote:

the second example in your post

the ${lua} function automatically puts "conky_" in front of the function name you set

Ahhhhhhhhh I remember reading that someplace.
Where? Don't remember... Thank you.

Last edited by Sector11 (2012-03-04 02:51:30)


#! Forum Moderator | To #! or not to #!?  That is the question!
#! Conky = 16 Threads & the Conky Archives | Conky PitStop | OHCG'er
StartPage -  protect your privacy   |   BBQ Linux

Online

#55 2012-03-23 18:18:30

mrpeachy
20% cooler
From: The Everfree Forest
Registered: 2009-11-08
Posts: 3,460

Re: HOW TO : using lua scripts in conky

HOW TO LUA

Part 13 USEFUL FUNCTIONS and  CODEU

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.

1. 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--of function

this fcuntion 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 function in the past, but 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 which we want the function to split the string up at
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 tabel 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

2. 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--local function

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 rememebr that it is only due to the way that conky and lua work together that you can have function belwo 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
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 less 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

OTHER FUNCTIONS
these are some function i have written or adapted from code i found

3 IMAGE DISPLAT 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--function image ##################################################################

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 streamline as possible
and i aslo wanted the ability to set default values so taht you dont have to enter every setting, everyry 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 oder either

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

does the same things 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 recieved by the function and put as seperate entries in a table called "im"
if we sent the info as described above, if we 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 not 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...
1. checks the table "im" for a value for x
2. 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"
3  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 equal 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 wouldnt need to enter a value for x

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

i sed 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

4. 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--local function
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--function out ###################################################################

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 but i am using it as a local function
a local function 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 wouldnt have to remember to put in 2 seperate function every time i wanted to use out()

think of it like a dependancy
out() requires the ability to use the col() function
i could put the col function as a seperate 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
so its built into the function that needs it!

ok thats it for this section

Last edited by mrpeachy (2012-09-01 17:15:57)

Offline

#56 2012-05-11 16:03:46

Peachy
New Member
Registered: 2012-05-11
Posts: 1

Re: HOW TO : using lua scripts in conky

Thank you for this. I have just finished part 1.
Taking it slow. I want to make sure I understand everything.

Offline

#57 2012-05-11 16:06:52

falldown
#! Samurai
Registered: 2011-09-01
Posts: 1,726

Re: HOW TO : using lua scripts in conky

Oh NO!!
MrPeachy... and Peachy!!
Now I'm really going to be confused!! big_smile

Welcome to #! Peachy!

Offline

#58 2012-05-11 16:59:05

mrpeachy
20% cooler
From: The Everfree Forest
Registered: 2009-11-08
Posts: 3,460

Re: HOW TO : using lua scripts in conky

^yes, that could be a little confusing!


hope everything is making sense peachy

Offline

#59 2012-05-27 22:07:40

1inux
New Member
Registered: 2012-05-27
Posts: 1

Re: HOW TO : using lua scripts in conky

I dont quite understand 'part 7', where exactly in the conky lua file do i put the segments of code in order to get the notification effect?

Offline

#60 2012-08-28 12:30:31

jed
#! CrunchBanger
From: Detachment 7
Registered: 2012-08-28
Posts: 191
Website

Re: HOW TO : using lua scripts in conky

@mrpeachy, thanks for the great tips n tricks about conky! I gave you a nod over at ubuntuforums for the help you gave me recently.  Thanks to you and Sector11 over there, I got a pretty good one going that I finally like a lot.  Even have figured out how to start it up after a 3 second delay when the laptop reboots or logs in.
Just wanted to Officially say thanks here on crunchbanglinux, as I did a lot of reading here for a lot of different things.  As a Linux user, you gotta love all the free support some of these better sites offer via their users.  It's why I'm using Linux smile  Well, not totally why, but hopefully if your reading this then you know what I mean!  Linux rules...
Jed

Offline

#61 2012-08-28 16:37:38

mrpeachy
20% cooler
From: The Everfree Forest
Registered: 2009-11-08
Posts: 3,460

Re: HOW TO : using lua scripts in conky

Hi jed
Saw your post over at the ubuntu thread, nicely done!
I'm always happy to see a new v9000 convert big_smile

Offline

#62 2012-09-01 04:28:24

mrpeachy
20% cooler
From: The Everfree Forest
Registered: 2009-11-08
Posts: 3,460

Re: HOW TO : using lua scripts in conky

Part 14 RUNNING CLI COMMANDS, TIMERS AND LINE EDITING

this is a general piece of code for running a cli command and storing the output in a string

local file = io.popen("command")
output = file:read("*a")
file:close()

say I wanted to get info about my partitions, I could run the "df-h" command like so

local file = io.popen("df -h")
output = file:read("*a")
file:close()

so if I were to do

print (output)

I would see in the terminal something like:

Filesystem            Size  Used Avail Use% Mounted on
/dev/sda1              19G  4.9G   13G  28% /
udev                  3.9G  4.0K  3.9G   1% /dev
tmpfs                 1.6G  1.1M  1.6G   1% /run
none                  5.0M     0  5.0M   0% /run/lock
none                  4.0G  288K  4.0G   1% /run/shm
/dev/sda5             459G  223G  213G  52% /home
/dev/sr0              6.9G  6.9G     0 100% /media/Belk_4e_IRDVD

first problem is that the "df -h" command is being run every conky cycle (just like if we were to use exec in the conkyrc)

to get lua to run the command in an execi type way, execute once per interval, then we need to set up a timer.

SETTING A TIMER

a lua timer runs on the output of the conky object ${updates}
in the conkyrc you have the line

update_interval 1

${updates} simply counts how may times conky has updated
we can get this output in lua through conky_parse

updates=tonumber(conky_parse("${updates}"))
interval=10
timer=(updates % interval)

In the first line I'm using tonumber so that the output of the conky_parse is set as a number instead of a string

The second line I have set the interval time.  This is number of updates so will only be equal to seconds if your update_interval in the conkyrc is set to 1

The third line is the counting mechanism.  What is going on here is that the number held in the string "updates" is being divided by the number held in the string "interval" and what is being output is the remainder.

So if updates=6 and interval=10
6/10 = 0 and 6/10ths
so timer=6

If updates=38 and interval=10
38/10 = 3 and 8/10ths
timer=8

updates=200, interval=10
timer=0

updates=1737, interval=60
timer=57
and so on. 

With interval=10, timer will be the numbers 0 to 9 in repeating order.
We can then use the output of timer in an if statement:

updates=tonumber(conky_parse("${updates}"))
interval=10
timer=(updates % interval)
if timer==0 then
--do codeX
end

timer will be 0 every 10 conky cycles and at that time codeX will be run.  So this is analogous to ${execi 10 code} in the conkyrc.

BUT one problem still remains.  Unlike ${execi 10}, the code in our if statement will not automatically run on conky start (or conky restart after saving the rc).  To get around this we have to think about how the lua script is being run by the rc.

A simple example lua script

require 'cairo'

print("this is outside of the function")

function conky_main()
if conky_window == nil then return end
local cs = cairo_xlib_surface_create(conky_window.display, conky_window.drawable, conky_window.visual, conky_window.width, conky_window.height)
cr = cairo_create(cs)
--#########################################
print ("this is inside the function")
--#########################################
cairo_destroy(cr)
cairo_surface_destroy(cs)
cr=nil
end--of function

run that code in the conkyrc like this:

conky settings above

lua_load /path/file.lua
lua_draw_hook_pre main

TEXT

watch the terminal as you launch conky with conky -c and you will see the following

mcdowall@mcdowall-desktop:~/Desktop$ conky -c ~/lua/conky_test
this is outside of the function
Conky: desktop window (e00022) is subwindow of root window (15d)
Conky: window type - normal
Conky: drawing to created window (0x2e00001)
Conky: drawing to double buffer
this is inside the function
this is inside the function
this is inside the function
this is inside the function
this is inside the function
this is inside the function
this is inside the function
this is inside the function

when conky starts or restarts after a save the entire lua script is read from top to bottom
so on conky start (and restart) we see "this is outside of the function", but ONLY on conky start

Once conky has started, and every conky update following,  only the code contained in the function "conky_main" is run so we see "this is inside the function" repeated every conky cycle.

We can use this to our advantage to activate lua code on conky start

NOTE - This feature can be used for lots of other things too.

require 'cairo'

conky_start=1

function conky_main()
if conky_window == nil then return end
local cs = cairo_xlib_surface_create(conky_window.display, conky_window.drawable, conky_window.visual, conky_window.width, conky_window.height)
cr = cairo_create(cs)
--#########################################
updates=tonumber(conky_parse("${updates}"))
interval=10
timer=(updates % interval)
if timer==0 or conky_start==1 then
print ("update number= "..updates)
print ("you will see this at conky start and then at 10 cycle intervals")
conky_start=nil
end--if timer
--#########################################
cairo_destroy(cr)
cairo_surface_destroy(cs)
cr=nil
end--of function

now you see this in the terminal:

mcdowall@mcdowall-desktop:~/Desktop$ conky -c ~/lua/conky_test
Conky: desktop window (e00022) is subwindow of root window (15d)
Conky: window type - normal
Conky: drawing to created window (0x2e00001)
Conky: drawing to double buffer
update number= 1
you will see this at conky start and then at 10 cycle intervals
update number= 10
you will see this at conky start and then at 10 cycle intervals
update number= 20
you will see this at conky start and then at 10 cycle intervals
update number= 30
you will see this at conky start and then at 10 cycle intervals

NOTE the line "conky_start=nil" as it is important.

even though the line "conky_start=1" only runs at startup, the string "conky_start" is retained within the lua script
if we were to put "print (conky_start)" into our function (above where we set it nil) then we would get "1" printed in the terminal
so unless we change the value of conky_start, it will retain the value of 1 and the if evaluation (if timer==0 or conky_start==1 then) will be passed every cycle and the code will be run every cycle

You could set conky_start to anything other than 1, but setting it to nil has the added benefit of deleting the variable.  Less variables floating around the better.

NOW that we can control our commands lets get back to running them!

we ran the "df -h" command and stored the output in a string BUT we want to make the information in that string usable. 

For example display the mount point for each item using cairo_show_text.  Or we want to take the use% for each entry and display that information as a bar or other indicator.  To do this we need to extract the various bits and pieces out of the string and into other strings or tables. 

One of the best methods for doing this in lua is the string.find command.
For example, to get the mount points for each partition listed from "df -h":

local file = io.popen("df -h")
output = file:read("*a")
file:close()
start,finish,mount1=string.find(output,"%%%s*(/[%d%a%p]*)\n")
start,finish,mount2=string.find(output,"%%%s*(/[%d%a%p]*)\n",finish)
start,finish,mount3=string.find(output,"%%%s*(/[%d%a%p]*)\n",finish)
print (mount1)
print (mount2)
print (mount3)

in the terminal:

/
/dev
/run

which are the first 3 mount points in the list given by "df -h"

THE HARD PART is what to put into the string.find command
and when writing code there are usually several ways to get the same result.

There are planty of resourcfes to learn about string.find and other string manipulation commands: http://www.gammon.com.au/forum/?id=6034
The 5.1 manual http://www.lua.org/manual/5.1/manual.html#5.4 and http://www.lua.org/manual/5.1/manual.html#5.4.1
The lua users wiki http://lua-users.org/wiki/StringLibraryTutorial

the way that I use string.find, 3 things are returned from the command in this order.
1. the position in the string where that match started
2. the position in the string where the match ended
3. the captured part of the string (the part that contains the info we want)

this is why I have started my lines:

start,finish,mount=

then the command itself:

string.find

and then we send the string.find command all the bits and pieces it needs inside round brackets ()
The first thing to send it is the string that contains the information we want to get out, which in this case is called "output"

The next part is where the matching happens.

LETS look at the results from "df -h"

Filesystem            Size  Used Avail Use% Mounted on
/dev/sda1              19G  4.9G   13G  28% /
udev                  3.9G  4.0K  3.9G   1% /dev
tmpfs                 1.6G  1.1M  1.6G   1% /run
none                  5.0M     0  5.0M   0% /run/lock
none                  4.0G  812K  4.0G   1% /run/shm
/dev/sda5             459G  223G  213G  52% /home
/dev/sr0              6.9G  6.9G     0 100% /media/Belk_4e_IRDVD

We need to identity a feature of the output that we can use in a match.  Ideally we need a feature to match before the data we want and a feature to match following the data

In this case preceding the mount point on each line is the "Use%" number.  This is the only place in a line where you see the % symbol, and for every line in the output the mount point for the partition is preceded by a % and then a space.

The mount point itself is the last thing in the line.  In this case a new line character is \n
so this gives us something to match after the mount point.

NOW we have to look at pattern matching
The standard patterns you can search for are:

 . --- (a dot) represents all characters. 
%a --- represents all letters. 
%c --- represents all control characters. 
%d --- represents all digits. 
%l --- represents all lowercase letters. 
%p --- represents all punctuation characters. 
%s --- represents all space characters. 
%u --- represents all uppercase letters. 
%w --- represents all alphanumeric characters. 
%x --- represents all hexadecimal digits. 
%z --- represents the character with representation 0. 

Important - the uppercase versions of the above represent the complement of the class. eg. %U represents everything except uppercase letters, %D represents everything except digits.

There are some "magic characters" (such as %) that have special meanings. These are:

^ $ ( ) % . [ ] * + - ?

If you want to use those in a pattern (as themselves) you must precede them by a % symbol.

eg. %% would match a single %

you can build your own pattern classes by using square brackets, eg.

[abc] ---> matches a, b or c
[a-z] ---> matches lowercase letters (same as %l)
[^abc] ---> matches anything except a, b or c
[%a%d] ---> matches all letters and digits
[%a%d_] ---> matches all letters, digits and underscore
[%[%]] ---> matches square brackets (had to escape them with %)

The repetition characters are:

+  ---> 1 or more repetitions (greedy)
*  ---> 0 or more repetitions (greedy)
-  ---> 0 or more repetitions (non greedy)
?  ---> 0 or 1 repetition only

The standard "anchor" characters apply:

^  ---> anchor to start of subject string
$  ---> anchor to end of subject string

SO lets look at the pattern matching I used

"%%%s*(/[%d%a%p]*)\n"

My data is preceded by "% " and that is what I am matching with "%%%s"

"%%" is a % character  (remember that % itself is a lua "magic" character and needs to be escaped using preceding %)

"%s" is a space character

CAPTURES

Captures are specified using round brackets ()
looking at my output I see that all of my mount points start with a back-slash "/" so I put this as the first character in my capture brackets.
One reason for this is that I DON'T want to capture the "Mounted on" from the first line.  Since there is no / in that line, it shouldn't match.

After the / there are many different things that might appear in the mount point of a partition.
In particular you might get any combination of Numbers, letters and punctuation
which are represented here with "[%d%a%p]*"
ie any combination of numbers, letters or punctuation repeated 0 or more times

you shouldn't get any spaces if you do have spaces in the names of partitions then you would need to add "%s" into the brackets

so my capture is as follows:

(/[%d%a%p]*)

following the capture is "/n" because I want to stop the string.find command when it reaches the end of the line and matches a newline character.

I will continue with explaining the string.find lines i used as well as other ideas on how to do the data extraction and methods of "automating" the process at a later date.
EDIT - UPDATE - I wrote this originally in LibreOffice Writer which reulted in some quotation marks not matching when you copy and paste the code into a lua script, it also changed -- (a comment in lua) to a long -
this should be fixed now.

Last edited by mrpeachy (2012-09-01 18:08:46)

Offline

#63 2012-09-01 19:44:30

mrpeachy
20% cooler
From: The Everfree Forest
Registered: 2009-11-08
Posts: 3,460

Re: HOW TO : using lua scripts in conky

Part 14.b LINE EDITING CONTINUED

here is the output of "df -h" as stored in the string output

Filesystem            Size  Used Avail Use% Mounted on
/dev/sda1              19G  4.9G   13G  28% /
udev                  3.9G  4.0K  3.9G   1% /dev
tmpfs                 1.6G  1.1M  1.6G   1% /run
none                  5.0M     0  5.0M   0% /run/lock
none                  4.0G  288K  4.0G   1% /run/shm
/dev/sda5             459G  223G  213G  52% /home
/dev/sr0              6.9G  6.9G     0 100% /media/Belk_4e_IRDVD

my first data extraction line:

start,finish,mount1=string.find(output,"%%%s*(/[%d%a%p]*)\n")
print (mount1) --> /
print (finish) --> 101

string.find finished matching me expressions at position 101

my second data extraction line

start,finish,mount2=string.find(output,"%%%s*(/[%d%a%p]*)\n",finish)
print (mount2) --> /dev

Using the value of "finish" from the previous match at the end of this string.find command tells string.find to START searching at that position onward.  The default, if not start position is given, is that string.find begins at position 1.  The result is that the second mount point is returned.

This could be repeated so on and so forth until you have all the mountpoints from "df -h"

BUT what if you didn't know how many lines you were dealing with? 
This will most likely be the case as partitions may be mounted or unmounted.

READING THE OUTPUT LINE BY LINE
this can be an extremely useful technique.  This is the general form for the code:

local file = io.popen("command")
    for line in file:lines() do
        --code
    end
file:close()

what this does is to take each line from the output of the command and apply the code to it individually.  For our "df -h" command we could do this:

local file = io.popen("df -h")
    for line in file:lines() do
    print ("this is a line "..line) --line is the name of the string that contains each line from the command "df -h"
    end
file:close()

and get this in the terminal:

this is a line Filesystem            Size  Used Avail Use% Mounted on
this is a line /dev/sda1              19G  4.9G   13G  28% /
this is a line udev                  3.9G  4.0K  3.9G   1% /dev
this is a line tmpfs                 1.6G  1.1M  1.6G   1% /run
this is a line none                  5.0M     0  5.0M   0% /run/lock
this is a line none                  4.0G  640K  4.0G   1% /run/shm
this is a line /dev/sda5             459G  223G  213G  52% /home
this is a line /dev/sr0              6.9G  6.9G     0 100% /media/Belk_4e_IRDVD

looking at the print command

print ("this is a line "..line)

I have used .. to join together some text "this is a line" with a string called line
The string named line holds each line from the output of the "df -h" command, one after another, in order.
This is a different kind of for loop.
the loop runs until it has read every line and applied any code within the loop
then the loop breaks and the rest of the code continues.

In the loop i simply had the text "this is a line" added onto the front of each line, hence the output.

Let's extract the "Used" value from each line
For this method I am going to extract the values into a table and I am going to put the table.

updates=tonumber(conky_parse("${updates}"))
interval=10
timer=(updates % interval)
if timer==0 or conky_start==1 then
used_table={}
local file = io.popen("df -h")
    for line in file:lines() do
    s,f,used=string.find(line,"[%d%p]*%u%s*([%d%p%a]*)%s")
    table.insert(used_table,used)
    end
file:close()
conky_start=nil
end
print (used_table[2]) --> 4.9G

this is the table I set up to receive the values "used_table={}"
it is important that the table is INSIDE the timer controlled section because whenever the script runs the line:

used_table={}

any contents in the table are deleted and the table is blanked.  So if the table was outside of the timer it would be blanked every cycle BUT data will only be written to the table once every 10 cycles (interval=10).  So 9 cycles out of 10 the table will be blank, which is no good.

here is the string.find line:

s,f,used=string.find(line,"[%d%p]*%u%s*([%d%p%a]*)%s")

I have shortened the names of the start and finish receiving strings to s and f

NOTE - if the results of the start and finish position of the match are of no interest string.match could be used as follows

used=string.match(line,"[%d%p]*%u%s*([%d%p%a]*)%s")

string.match only returns the captured part of the string

BUT i'm going to stick with string.find

the first thing we feed the string.find command is the string that holds the information we want to look at: line

Then looking at the output of "df -h" we need to identify the before and after features to match

/dev/sda1              19G  4.9G   13G  28% /

BEFORE the "Used" value is the "Size" value. 
The Size value looks to be a combination of numbers and punctuation (decimal point) followed by an upper case letter denoting the unit followed by one or more spaces.

So that is what i put into my matching statement before my capture brackets: "[%d%p]*%u%s*"
[%d%p]* = any combination of 0 or more numbers and punctuation
%u = a capital letter
%s* = 0 or more spaces

AFTER the "Used" value there are always at least one space, and that is what i will use to end the match after the capture brackets: %s

The capture brackets themselves: ([%d%p%a]*)
any combination of 0 or more numbers, punctuation and letters

The loop cycles through the lines, extracts the Used value and then:

table.insert(used_table,used)

puts the values into the table in order.

In the above case the first entry in the table is actually "ilesystem"
which, by applying the search criteria to the very first line:

Filesystem            Size  Used Avail Use% Mounted on

should be self explanatory.

you could look at what was in the table like this:

table_length=tonumber(#used_table)
for i=1,table_length do
print (table[i])
end

NOTE - IF we only wanted to get the number part of the Used value, there is a catch in this case:
if the Used value is greater than 0 the value always ends in an uppercase letter BUT when Used=0 as in the line:

none                  5.0M     0  5.0M   0% /run/lock

we only have the 0, and no letter. 
This, however would work to get just the number:

s,f,used=string.find(line,"[%d%p]*%u%s*([%d%p]*)%u*%s")

However, the expression within the capture brackets no longer matches the first line from "df-h"
so

print(used_table[1]) --> 4.9 (the value for / partition)

Offline

#64 2012-09-02 02:19:24

mrpeachy
20% cooler
From: The Everfree Forest
Registered: 2009-11-08
Posts: 3,460

Re: HOW TO : using lua scripts in conky

Part 14.c GETTING DATA FROM WEB PAGES

The same methods as used to get the data from the output of "df -h"  can be used to extract information from a web page.
The command to use here would be:

local file = io.popen("curl 'web address'")
output = file:read("*a")
file:close()

NOTE - be careful with your quotation marks.  The curl command requires that you enclose the web address you want to access within quotes, but the lua code also requires that the entire command you want to run be enclosed in quotes.
Both types of quotes (double " and single ' ) can be used to get around this requirement and it doesn't matter which way around you use them ie enclose the command in one type and the web address in another. 

If you use a text editor like gedit, once you save your file as a .lua, you will see that gedit uses different colors to highlight different parts of the text
For me, quoted text in lua shows pink in gedit  (medit = pink, geany = yellow).

There are several ways you could do this
you can set the web address as a string (for example if you wanted to construct a settings section separate to the main code)
this can help you get round any problems related to quotes also

updates=tonumber(conky_parse("${updates}"))
interval=100
timer=(updates % interval)
if timer==0 or conky_start==1 then
used_table={}
web="http://crunchbanglinux.org/forums/search/recent/"
file = io.popen("curl "..web)
output=file:read("*a")
file:close()
conky_start=nil
print (output)
end

what gets printed in the terminal is the contents of "output" which is the entire source code for the page

NOW we can start working on getting the data out.
Say we want to get the topmost thread title from the "Active Topics" page on the crunchbang forum http://crunchbanglinux.org/forums/search/recent/

The first thing is to open the page, once as you would view it regularly and once aftyer right clicking somewhere on the page and selecting "View Page Source"

Right now, the top thread in the list is titled:

Indefinite Hang on Reboot/Shutdown

Go to the source code and search for those exact terms, then look around a bit at the code.

    </div>
    <div class="main-content main-forum forum-noview">
        <div class="main-item odd main-first-item new">
            <span class="icon new"><!-- --></span>
            <div class="item-subject">
                <h3 class="hn"><span class="item-num">1</span> <a href="http://crunchbanglinux.org/forums/topic/21773/indefinite-hang-on-rebootshutdown/">Indefinite Hang on Reboot/Shutdown</a> <span class="item-nav">( <em class="item-newposts"><a href="http://crunchbanglinux.org/forums/topic/21773/indefinite-hang-on-rebootshutdown/new/posts/" title="Go to the first new post since your last visit.">New posts</a></em> )</span></h3>
                <span class="item-starter">by <cite>drewdle</cite></span>
            </div>

Below that you will see the other topics in the list.
The first thing we need to look for is something unique that identifies this topic as the first one...
I see:

class="item-num">1</span>

before the info I want, and when i search for that expression I find that it is unique.  The only downside is the quotes, which might make writing a matching expression more difficult.  Ignoring the quoted part:

>1</span>

is also unique, so we will use that.

ALSO directly before the info I want there is this:

/">

This appears before the title of every entry in the list and can help us to get only the title out from the code.

And directly after the info I want I see:

</a> <span class=

this appears to be a constant, so should give us a predictable place to stop our search

THE FIRST THING to do is to replace any actual spaces in our search terms with %s
so "</a> <span class=" becomes "</a>%s<span%sclass="
then replace any other troublesome characters:
/"> becomes /%p> (%p is a punctuation character)

another thing to look out for is if there are any lua magic characters that need to be escaped with %

lets put together our search pattern:

BEFORE the capture brackets we have:

>1</span> followed by any combination of 0 or more numbers, letters, punctuation and spaces until we get to /">

which becomes:

>1</span>[%d%a%p%s]*/%p>

AFTER the capture brackets we have

</a> <span class=

which becomes:

</a>%s<span%sclass=

INSIDE the capture brackets we are going to match any combination of 0 or more numbers, letters, punctuation and spaces:

([%d%a%p%s]*)

The entire code to get the first entry from the "Active topics" page on the crunchbang forum is then:

updates=tonumber(conky_parse("${updates}"))
interval=100
timer=(updates % interval)
if timer==0 or conky_start==1 then
used_table={}
local web="http://crunchbanglinux.org/forums/search/recent/"
local file = io.popen("curl "..web)
output=file:read("*a")
file:close()
local s,f,topic1=string.find(output,">1</span>[%d%a%p%s]*/%p>([%d%a%p%s]*)</a>%s<span%sclass=")
conky_start=nil
print (topic1)
end

which outputs in the terminal:

mcdowall@mcdowall-desktop:~/Desktop$ conky -c ~/lua/conky_test
Conky: desktop window (e0aafa) is subwindow of root window (15d)
Conky: window type - normal
Conky: drawing to created window (0x2a00001)
Conky: drawing to double buffer
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 38635    0 38635    0     0  99067      0 --:--:-- --:--:-- --:--:--  118k
Indefinite Hang on Reboot/Shutdown

these lines:

  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 38635    0 38635    0     0  99067      0 --:--:-- --:--:-- --:--:--  118k

show curl working

Last edited by mrpeachy (2012-09-03 03:02:11)

Offline

#65 2012-09-02 21:36:07

falldown
#! Samurai
Registered: 2011-09-01
Posts: 1,726

Re: HOW TO : using lua scripts in conky

Peachy
I think you have enough typed out material for a book and at some point I will get around to reading it all.

Offline

#66 2012-09-02 22:29:01

mrpeachy
20% cooler
From: The Everfree Forest
Registered: 2009-11-08
Posts: 3,460

Re: HOW TO : using lua scripts in conky

*wonders if anyone has read it all* lol
by the way, if anyone has been following along and has a request about how to do something with lua in conky, let me know.

Offline

#67 2012-09-02 23:14:09

Sector11
77345 ¡#
From: SR11 Cockpit
Registered: 2010-05-05
Posts: 11,433
Website

Re: HOW TO : using lua scripts in conky

mrpeachy wrote:

*wonders if anyone has read it all* lol
by the way, if anyone has been following along and has a request about how to do something with lua in conky, let me know.

I have read every instalment as they were made, and re-read them as I edited them into my massive 4,796 line text file that still needs; Part 14.c GETTING DATA FROM WEB PAGES:

~/Conky/LUA/mrpeachy/HowTo-Using-LUA-in-Conky.txt

Now let's not talk about my retention ability nor the number of times I've said to myself, "yes, that's as clear as mud now." However  ... just so you know, I have read it!

And that be a big tongue to falldown!  lol

and MrP - you do not weant me to ask questions on the things I don't understand ... at least not all at once. lol lol or you'll be roll 'OH NO! Not again!' roll


#! Forum Moderator | To #! or not to #!?  That is the question!
#! Conky = 16 Threads & the Conky Archives | Conky PitStop | OHCG'er
StartPage -  protect your privacy   |   BBQ Linux

Online

#68 2012-09-02 23:17:24

Sector11
77345 ¡#
From: SR11 Cockpit
Registered: 2010-05-05
Posts: 11,433
Website

Re: HOW TO : using lua scripts in conky

Reference:

local file = io.popen("curl 'web address'")
output = file:read("*a")
file:close()

what about wget?  Can that be used?  Would it be better?

local file = io.popen("wget 'web address'")
output = file:read("*a")
file:close()

just a thought

EDIT: RE: mrpeachy & gedit

For me, quoted text in lua shows pink.

Sector11: medit = pink, geany = yellow

Last edited by Sector11 (2012-09-02 23:22:26)


#! Forum Moderator | To #! or not to #!?  That is the question!
#! Conky = 16 Threads & the Conky Archives | Conky PitStop | OHCG'er
StartPage -  protect your privacy   |   BBQ Linux

Online

#69 2012-09-03 02:59:08

mrpeachy
20% cooler
From: The Everfree Forest
Registered: 2009-11-08
Posts: 3,460

Re: HOW TO : using lua scripts in conky

Sector11 wrote:

Reference:

local file = io.popen("curl 'web address'")
output = file:read("*a")
file:close()

what about wget?  Can that be used?  Would it be better?

I have used wget, for example to download images from a web page
It is just the case that I have used curl in the past and I am more familiar with how it works

I cant say if there is a benefit of one vs the other (found this page http://daniel.haxx.se/docs/curl-vs-wget.html although i cant say i understand a lot of it big_smile )

*Added a note about other colors of quoted text

Last edited by mrpeachy (2012-09-03 03:02:44)

Offline

#70 2012-09-03 23:00:13

Sector11
77345 ¡#
From: SR11 Cockpit
Registered: 2010-05-05
Posts: 11,433
Website

Re: HOW TO : using lua scripts in conky

mrpeachy wrote:
Sector11 wrote:

Reference:

local file = io.popen("curl 'web address'")
output = file:read("*a")
file:close()

what about wget?  Can that be used?  Would it be better?

I have used wget, for example to download images from a web page
It is just the case that I have used curl in the past and I am more familiar with how it works

I cant say if there is a benefit of one vs the other (found this page http://daniel.haxx.se/docs/curl-vs-wget.html although i cant say i understand a lot of it big_smile )

*Added a note about other colors of quoted text

I think if you are comfortable with curl you picked the best.  big_smile

wget http://someplace.com

works great in a terminal though.

Or to get something from a dropbox - like falldown's LCARS.tar.gz file.  SUPER!


#! Forum Moderator | To #! or not to #!?  That is the question!
#! Conky = 16 Threads & the Conky Archives | Conky PitStop | OHCG'er
StartPage -  protect your privacy   |   BBQ Linux

Online

#71 2012-11-06 21:14:56

borntwisted
New Member
From: Wales
Registered: 2012-11-06
Posts: 1
Website

Re: HOW TO : using lua scripts in conky

Thanks for taking the time to explain all this mrpeachy, used lua in conky for quite a while but not fully understood it apart from minor modification to other people's scripts, so really appreciate it being explained smile

There might be a minor typo in the first post, think you meant string1*string2, otherwise it would be a loop?

mrpeachy wrote:

Using Lua scripts in conky

eg

string1=5
string2=9
string3=string1*string3

in this case string3 holds the value 45

First post, so don't hate me if I've got it wrong or it has been previously mentioned, just trying to make it easier for noobs like me  wink

Offline

#72 2012-11-06 21:18:59

mrpeachy
20% cooler
From: The Everfree Forest
Registered: 2009-11-08
Posts: 3,460

Re: HOW TO : using lua scripts in conky

borntwisted wrote:

Thanks for taking the time to explain all this mrpeachy, used lua in conky for quite a while but not fully understood it apart from minor modification to other people's scripts, so really appreciate it being explained smile

There might be a minor typo in the first post, think you meant string1*string2, otherwise it would be a loop?

mrpeachy wrote:

Using Lua scripts in conky

eg

string1=5
string2=9
string3=string1*string3

in this case string3 holds the value 45

First post, so don't hate me if I've got it wrong or it has been previously mentioned, just trying to make it easier for noobs like me  wink

thanks for pointing that out, ill go change it
also glad i could help smile

Offline

#73 2012-11-23 02:06:19

dura
Bloated Gimp
From: interzone
Registered: 2012-09-15
Posts: 2,106

Re: HOW TO : using lua scripts in conky

wow

Offline

#74 2013-03-07 17:05:53

Gordon
#! CrunchBanger
From: Blackpool, Lancashire, UK
Registered: 2012-05-22
Posts: 238

Re: HOW TO : using lua scripts in conky

Hi mrpeachy,

I am trying to follow your howto and have come across a problem that I have no idea how to fix it or what it is. this is what I get when I run conky in terminal

gordon@crunchbang:~$ conky
WARNING: gnome-keyring:: couldn't connect to: /home/gordon/.cache/keyring-f9X7tR/pkcs11: No such file or directory
Conky: missing text block in configuration; exiting
***** Imlib2 Developer Warning ***** :
	This program is calling the Imlib call:

	imlib_context_free();

	With the parameter:

	context

	being NULL. Please fix your program.

and this is what I have in lua

-- this is a lua script for use in conky

require 'cairo'

function conky_main()  -- start of main function

if conky_window == nil then return end
local cs = cairo_xlib_surface_create(conky_window.display, conky_window.drawable, conky_window.visual, conky_window.width, conky_window.height)
cr = cairo_create(cs)
local updates=tonumber(conky_parse('${updates}'))
if updates>5 then -- start of updates
-- ####################################
ptint ('hello world')
-- ####################################
end -- if updates
cairo_destroy(cr)
cairo_surface_destroy(cs)
cr = nil
end  -- of main function

which is what I think you say is the minimum that you need. What have I got wrong please ?


Cheers smile smile
Gordon
Using Janice Testing at present also sid and systemd and  VSIDO
A7N8X delux motherboard, 1 GB ram, AMD ATHLON XP 2800+ ( 2255 Mhz ), Nvidia Geforce PNY 62000 graphics card

Offline

Be excellent to each other!

#75 2013-03-08 05:48:03

ansem_of_nexus
#! CrunchBanger
Registered: 2012-09-19
Posts: 234

Re: HOW TO : using lua scripts in conky

@Gordon there is a response for you over in The New Monster Conky Thread


You can find my work here

Make everything ok button

Offline

Board footer

Powered by FluxBB

Copyright © 2012 CrunchBang Linux.
Proudly powered by Debian. Hosted by Linode.
Debian is a registered trademark of Software in the Public Interest, Inc.

Debian Logo