Hammerspoon hs.application:kill() not callable - lua

Trying to get Hammerspoon to quit (kill) the Music app in OS X whenever it opens. (This application has been installed by Apple in such a way as to make it very difficult to alter and it launches whenever a bluetooth device is connected. Annoying bloatware, basically.) So, I cribbed this from the Hammerspoon "Getting started" page https://www.hammerspoon.org/go/...
function applicationWatcher(appName, eventType, appObject)
if (eventType == hs.application.watcher.launched) then
if (appName == "Music") then
hs.application:kill()
end
end
end
appWatcher = hs.application.watcher.new(applicationWatcher)
appWatcher:start()
This correctly responds to the Music app being launched, but it errors out like so... ERROR: LuaSkin: hs.application.watcher callback: /Users/seancamden/.hammerspoon/init.lua:142: method 'kill' is not callable (a nil value)
How I can make this method callable? Or, what is the right way to do this?
https://www.hammerspoon.org/docs/hs.application.watcher.html
https://www.hammerspoon.org/docs/hs.application.html#kill

your code is pretty much right, there is only one mistake. You used the global module hs.application and tried to call an object method :kill() from it. You would have to instantiate a new object first to be able to call it's kill method. For example: hs.application.get(appName):kill().
However, the watcher already provides you with the application object that called the function as appObject. So appObject:kill() is what you are looking for.
function applicationWatcher(appName, eventType, appObject)
if (eventType == hs.application.watcher.launched) then
if (appName == "Music") then
appObject:kill()
end
end
end
appWatcher = hs.application.watcher.new(applicationWatcher)
appWatcher:start()
Tested here on MacOS BigSur

Related

Discordia bot DM sending breaks my script

I am trying to make a bot for my server on discord using Discordia, but when I try to use member:send(str), all I get is Uncaught Error: C:/luvit/deps/coro-channel.lua:62: C:/luvit/deps/discordia/libs/containers/User.lua:91: attempt to call method 'getPrivateChannel' (a nil value)
it does send the dm, but then the code breaks and the bot doesn't run anymore, how can I fix this?
member is a variable that gets the member from message
local member = message.member
I am able to recreate the issue, albeit with a different error that I suspect is due to me not having all your code to debug with.
The bot will send the DM and post a message, then crash due to error.
You have this code:
if message.content:lower() == prefix..'createdm' then
message.channel:send("<#!"..memberid.."> ".. "Sent!")
message.member:send("test") --message.member is able to inherit the send method from message.author
end
I don't know how you find memberid, so I defined it like this:
memberid = message.member:__hash()
It is called every time a message is sent, and it sends a message. This means the bot is going to call this and read its own messages. While the bot will not continue into the if statement because its message is not <prefix>createdm, it will still try to get memberid and evaluate the if statement. I do not know how bot users differ from human users in their account metadata, but I strongly suspect there is some difference and this is your issue.
I believe adding this to your code, at the beginning of your message callback (before your do anything else to evaluate a message) will fix your problem.
if message.author == client.user then
return
end
client here is whatever you assigned discordia.Client() to.
if message.content:lower() == prefix..'createdm' then
message.channel:send("<#!"..memberid.."> ".. "Sent!") -- member.id !!!
message.member:send("test") --message.member is able to inherit the send method from message.author
end

Is there something like "awful.client.focus.global_byidx()"?

I have two monitors and I would like to change client focused by shortcut. Right now I have awful.client.focus.byidx(1) but it only changes clients on one monitor. I know there is awful.client.focus.global_bydirection("right") that works on multiple screens but it only goes to one direction and it stops working when get to last client. I like awful.client.focus.byidx(1) behavior which loops through all clients, so from the last client it goes to the first one.
I would like to use a hybrid between: going through clients as in awful.client.focus.byidx(1) but on all monitors/screens like awful.client.focus.global_bydirection("right") does. Is there a function that would have that behavior so I could use it? If not, do you know how could I achieve that goal?
First, let's look at how awful.client.focus.byidx is implemented.
The function itself calls awful.client.next and then focused the returned client, if any is found:
https://github.com/awesomeWM/awesome/blob/9781f14b105ee700c5bca339bf49bb52d2cca4b5/lib/awful/client/focus.lua#L65-L71
awful.client.next is implemented here: https://github.com/awesomeWM/awesome/blob/9781f14b105ee700c5bca339bf49bb52d2cca4b5/lib/awful/client.lua#L262-L284
It does the following:
line 263: Get the currently focused client
line 267: Get all visible clients on the screen of the visible client
line 270-274: Filter out unfocusable clients from the list
line 277 - 278: Find the focused client in the resulting list
line 280: Get the client at the wanted offset and return it
So, your request sounds like you only need to change one step here: Get the list of all visible clients instead of only those at the currently focused screen.
To get that list, you need to call awful.client.visible with nil instead of a specific screen.
Untested code:
function next_global(i, sel, stacked)
sel = sel or client.focus
if not sel then return end
local cls = awful.client.visible(nil, stacked)
local fcls = {}
for _, c in ipairs(cls) do
if awful.client.focus.filter(c) or c == sel then
table.insert(fcls, c)
end
end
cls = fcls
for idx, c in ipairs(cls) do
if c == sel then
return cls[gears.math.cycle(#cls, idx + i)]
end
end
end
function focus_byidx_global(i, c)
local target = next_global(i, c)
if target then
target:emit_signal("request::activate", "client.focus.byidx", {raise=true})
end
end
I don't know which version of AwesomeWM you are using. If in doubt, look at the installed files in /usr/share/awesome/lib/ and copy the code from there, then change it.
(A little more ugly solution would be something like the following, even though it requires less code; I leave it as an exercise to the reader to figure out what this does, but note that this "breaks stuff" in case a Lua error occurs and the monkey-patching becomes permanent)
function focus_byidx_global(i, c)
local old = awful.client.visible
awful.client.visible = function(_, s) return old(nil, s) end
awful.client.focus.byidx(i, c)
awful.client.visible = old
end

How to determine if sysdig field exists or handle error if it doesn't

I'm using Sysdig to capture some events and have a small chisel (LUA script) to capture and format the events as necessary. On the on_init() I'm requesting fields like so :
f_field = chisel.request_field("<field>")
My question is how can I check if a field exists before requesting it? I'm going to use a new field only just released on 0.24.1 but ideally I'd like my chisel to continue to work on older versions of sysdig without this field. I've tried wrapping the call to chisel.request_field in a pcall() like so :
ok, f_field = pcall(chisel.request_field("<field>"))
and even implementing my own "get_field" function :
function get_field(field)
ok, f = pcall(chisel.request_field(field))
if ok then return f else return nil end
end
f_field = get_field("<field>")
if f_field ~= nil then
-- do something
end
but the error ("chisel requesting nonexistent field <field>") persists.
I can't see a way to check if a field exists but I can't seem to handle the error either. I really don't want multiple versions of my scripts if possible.
Thanks
Steve H
You're almost there. Your issue is in how you're using pcall. Pcall takes a function value and any arguments you wish to call that function with. In your example you're passing the result of the request_field function call to pcall. Try this instead..
ok, f = pcall(chisel.request_field, "field")
pcall will call the chisel method with your args in a protected mode and catch any subsequent errors.

Checking if an instance *doesn't* exist -> "Not a valid member"

"checkin is not a valid member of PlayerGui" at line 2
function onClick(plr)
if game.Players[plr.Name].PlayerGui.checkin ~= nil then
print('player already has gui')
else
if game.ServerStorage.Players[plr.Name].Value == 0 then
local gui = game.ServerStorage.GUIs.checkin:Clone()
gui.Parent = plr.PlayerGui
print('fresh gui being handed to '.. plr.Name)
end
end
end
script.Parent.ClickDetector.MouseClick:connect(onClick)
If a member doesn't exist on an instance, Roblox will immediately throw an error.
If you're not sure if a child of a given name exists, use :FindFirstChild(name). Rather than throw an error, it just returns nil.
Note that MouseClick already gives a player, so doing game.Players[plr.Name] is really redundant.
if plr.PlayerGui:FindFirstChild("checkin") then
It's best practice to not handle GUIs on the Server. Instead, you can communicate to LocalScripts what they need to show using RemoteFunctions/RemoteEvents.

Control flow in Lua

I have a problem which i suppose must be very common and most of you would have faced it.
I have written a program in lua, say main.lua which on receiving key event should modify the coordinates and display the geometry figure.
This lua code calls reg.c, where it kind of registers.
Now in reg.c i have a function engine which receives the key pressed and passes it to the lua function responsible for key handling.
But by the time key event comes, lua code is done with the registration and exits, thus the call from engine() becomes illegal memory access leading to segmentation fault.
Also i suppose we can't have lua call hanging in reg function, and call engine function from somewhere else.
Then what should be the solution, please guide me through this.
#jacob: here is the prototype of what i am trying to achieve:
function key_handler() //this function will get the latest key pressed from some other function
{
draw.image();
draw.geometry();
...
...
while(1)
{
//draw Points until some condition goes wrong
}
}
Now, once entered into key_handler, while he is busy drawing the points unless and until the failing condition occurs, i am unable to receive key pressed till that time.
I hope this explanation is much simpler and have made my point, and will help others to understand the problem.
I am really sorry, but i am not good at expressing or making others understand.
One more thing, i ahve followed the C syntax to explain, however this is completely implemented in lua
Your code snippet is still largely non-informative (ideally one should be able to just run your code in a stock Lua interpreter and see your problem). If you're describing a Lua problem, use Lua code to describe it.
However I'm beginning to see where you want to go.
The thing you need to could do is have a coroutine that's called in your key handler, which passes an argument back to your handler:
function isContinue() --just to simulate whatever function you use getting keypresses.
-- in whatever framework you're using there will probably be a function key_pressed or the like.
print('Initialize checking function')
while true do
print('Continue looping?')
local ans = io.read():match('[yY]')
local action
if not ans then
print('Do what instead?')
action = io.read()
if action:match('kill') then -- abort keychecker.
break
end
end
coroutine.yield(ans,action)
end
print('finalizing isContinue')
return nil,'STOP' -- important to tell key_handler to quit too, else it'll be calling a dead coroutine.
end
function key_handler()
local coro = coroutine.create(isContinue)
local stat,cont,action
while true do
print'Draw point'
stat,cont,action = coroutine.resume(coro)
if not stat then
print('Coroutine errored:',cont)
elseif not cont then
print('isContinue interrupted keyhandler')
print("We'll "..action.." instead.")
break
end
end
print('finalizing key_handler')
end
key_handler()
-- type something containing y or Y to continue, all else aborts.
-- when aborting, you get asked what to do instead of continuing,
--- with "kill" being a special case.
This should be self explanatory. You should probably take a good look at Programming in Lua, chapter 9: Coroutines.
The big difficulty (well, if you're not accustomed to collaborative threading) is that a coroutine should yield itself: it's not the calling function that's in charge of returning control.
Hope this helps you.

Resources