This skin demonstrates how you can "tail" some number of lines from a text file, like a log file or to-do list or any other file you would like to see some number of the "most recent" items added to the bottom of the file, in reverse order.
This uses a very simple Lua script to read the file. The Lua then sets some number of String measures in the skin that are in a sense acting as "child" measures to the Lua Script measure. The meters then use the values of those String measures to display the lines.
You can simply change the file you want to read in [Variables] and use this as is, or feel free to tear it apart to use the underlying functionality in your skin.
I think it is pretty easy to follow what it is doing, but feel free to ask any questions.
Note that you easily could add IfMatch conditions to the String measures, which would for instance allow you to monitor for "error" in a log file, and set a font color different or any other action you like. You could also use RegExpSubstitute to replace text in the line, so for instance you could remove unwanted tabs or spaces, remove the first "xx" characters of the line, or any other change you might want to make with a regular expression search-and-replace.
Important: If you are going to have Unicode characters in the text file you are reading, that file MUST be encoded in UTF-8 with or without BOM. That is the only encoding supported by Lua when reading external Unicode files.
It is currently September 7th, 2024, 11:48 pm
TailFile
-
- Developer
- Posts: 22715
- Joined: April 19th, 2009, 11:02 pm
- Location: Fort Hunt, Virginia, USA
TailFile
You do not have the required permissions to view the files attached to this post.
-
- Developer
- Posts: 22715
- Joined: April 19th, 2009, 11:02 pm
- Location: Fort Hunt, Virginia, USA
Re: TailFile
Updated the Lua code to use a vastly more efficient method for reading the last N lines of a large file. The Lua code is based on work by Brian in This post.
-
- Posts: 1
- Joined: February 23rd, 2022, 9:56 am
Re: TailFile
Hi jsmorley,
thanks for the great skin!
It looks very promising. I was trying to tweak it to my purpose and I noticed during testing that it crashes the whole RainMeter when the source file has no data. Any idea how to prevent this?
Regards,
PickNick
thanks for the great skin!
It looks very promising. I was trying to tweak it to my purpose and I noticed during testing that it crashes the whole RainMeter when the source file has no data. Any idea how to prevent this?
Regards,
PickNick
-
- Posts: 588
- Joined: February 28th, 2011, 3:20 pm
- Location: Vienna, Austria
Re: TailFile
As it is about 2 months since you asked for preventing rainmeter crashing TailFile i had a look at it and made a change to TailFile.lua which just do nothing with the skin but returning -1 if it is a file with 0 bytes.
Technically the seek-function returns nil which i query. As the forum prevents lua-files to be attached to posts you have to copy/paste the content by yourself. Maybe there are some more clever lua-solutions to this but it is just straight forward.
Technically the seek-function returns nil which i query. As the forum prevents lua-files to be attached to posts you have to copy/paste the content by yourself. Maybe there are some more clever lua-solutions to this but it is just straight forward.
Code: Select all
function Initialize()
fileToRead = SKIN:GetVariable('FileToRead')
linesToTail = tonumber(SKIN:GetVariable('LinesToTail'))
childPrefix = SKIN:GetVariable('ChildPrefix')
end
function Update()
local inputFile = assert(io.open(fileToRead, 'r'))
local singleChar, lineText
local bytePosition = -1
local i = 1
local tooFewLines = false
repeat
if inputFile:seek('end', bytePosition - 1) == nil then
tooFewLines = true;
else
singleChar = inputFile:read(1)
if singleChar == '\n' then
lineText = inputFile:read(-bytePosition)
if lineText then
lineText = string.gsub(lineText, '\r', '')
SKIN:Bang('!SetOption', childPrefix..i, 'String', string.match(lineText, '^(.-)\n'))
SKIN:Bang('!UpdateMeasure', childPrefix..i)
i = i + 1
bytePosition = bytePosition - 1
end
end
bytePosition = bytePosition - 1
end
until (tooFewLines or i > linesToTail)
io.close(inputFile)
SKIN:Bang('!UpdateMeter', '*')
SKIN:Bang('!Redraw')
return 1
end
-
- Posts: 148
- Joined: August 16th, 2013, 12:47 pm
Re: TailFile
Is there a way the Lua could be modified to only match lines that begin with a certain string? In my case I'm wanting to match a particular Unicode character (let's say it's ❤) on certain lines.
I tried using if string.match(lineText, "❤") then on line 24 of ikarus' version of the script (line 21 of the original) and alternatively string.find in the same way but it returned the same results, so I'm obviously not looking at this the right way.
Also if this should be its own thread just let me know.
I tried using if string.match(lineText, "❤") then on line 24 of ikarus' version of the script (line 21 of the original) and alternatively string.find in the same way but it returned the same results, so I'm obviously not looking at this the right way.
Also if this should be its own thread just let me know.
-
- Rainmeter Sage
- Posts: 2734
- Joined: March 23rd, 2015, 5:26 pm
Re: TailFile
This should definitely not be part of a thread from 2015, but since someone else dug it up from the grave a year ago, then maybe OK... That said, your problem might be explained here: Unicode in Rainmeter, specifically the section "Using Unicode with Lua scripting".Crest wrote: ↑April 30th, 2023, 12:05 pm Is there a way the Lua could be modified to only match lines that begin with a certain string? In my case I'm wanting to match a particular Unicode character (let's say it's ❤) on certain lines.
I tried using if string.match(lineText, "❤") then on line 24 of ikarus' version of the script (line 21 of the original) and alternatively string.find in the same way but it returned the same results, so I'm obviously not looking at this the right way.
Also if this should be its own thread just let me know.
-
- Posts: 148
- Joined: August 16th, 2013, 12:47 pm
Re: TailFile
Hmm, I have all my Lua saved with UTF-16 with BOM and the Lua can output Unicode to the skin and debug Log. I originally assumed it was some logic I was overlooking.SilverAzide wrote: ↑April 30th, 2023, 3:35 pmYour problem might be explained here: Unicode in Rainmeter, specifically the section "Using Unicode with Lua scripting".
Edit: I realize now that lineText is returning all the lines at that point and that string.match(lineText, '^(.-)\n') later is what is outputting just the single line itself, so now I have a bit clearer understanding.
Edit 2: okay, have it working now. Changed from line 24 of ikarus' version like so (where beginSubstring is a variable defined with the desired Unicode character beforehand in the Lua):
Code: Select all
if lineText then
lineText = string.gsub(lineText, '\r', '')
lineTextSingle = string.match(lineText, '^(.-)\n')
if string.match(lineTextSingle, '^'..beginSubstring) then
SKIN:Bang('!SetOption', childPrefix..i, 'String', lineTextSingle)
SKIN:Bang('!UpdateMeasure', childPrefix..i)
i = i + 1
bytePosition = bytePosition - 1
end
end