简体   繁体   中英

What does this piece of lua code from awesome wm do?

Take a look at this code:

local urgent = {}

local capi =
{
    client = client,
}

local client
do
    client = setmetatable({}, {
        __index = function(_, k)
            client = require("awful.client")
            return client[k]
        end,
        __newindex = error -- Just to be sure in case anything ever does this
    })
end

I'm having trouble understanding what it does. It's from the awesome-wm project. These are the things I'm having trouble understanding:

  1. client = client in the declaration of capi
  2. setmetatable stuff inside do-end
  1. client = client in the declaration of capi

This is defining what portion of the capi is available in this file's scope, If you look at the client.lua file you will see that the capi defined in it has client, mouse, screen, and awesome.

For each item defined in the capi table there is a corresponding .c file. These files define objects such as client . urgent.lua has visibility of that object, likely it is a global variable, that is how we can set client = client the second client refers to the global variable.

Here is an example of 2 files:

main.lua

bar = "Hello World!"

local foo = require('foo')

print(foo.bar)

foo.lua

local foo = {
    bar = bar
}
return foo

The print function in main.lua will result in Hello World!

  1. setmetatable stuff inside do-end

Here by warping the setmetatable in a do-end block the code is executing in a restricted scope. This is normally done to contain the block's local variables so that they do not persist after the code's execution.

That said that is not the purpose of this block as the block has no local variables. As I see it, the blocking is simply to show that the object being modified is the local variable of client and not the global variable of client .

Additionally the metatable here is used to prevent circular dependency loops, this is mentioned comments in some of the places where similar code appears in the project, such as client.lua where local screen is defined.

@Nifim answer is excellent. I just want to add more context on why this code exist in its proper historical context. Before Lua 5.2, the module system was different. There was a magic module() function defined in the core Lua library. When you made a module, you had to first make local version of all global variables before calling module() because otherwise it would run in its own global environment. "capi" stands for "Core API" or "C (language) API" depending on the weather. If Awesome was written today with all the knowledge we now have, there would not be a public "C language" API and they would always be hidden in the private section to increase flexibility. Right now setting "c.my_own_property" do a couple round trips between capi.client and awful.client just to accommodate all the legacy constraints.

Now, the metatable magic is a Lua pattern called meta-lazy-loading. Because the urgent is a submodule of awful.client , it cannot directly import awful.client without causing a circular dependency. Over time, as Awesome APIs became better defined, more and more refactoring were made and they often introduced weird dependencies to maintain some degree of backward compatibility. In the best universe, we would have disregarded all users config and just re-engineered the whole code to avoid these circular dependencies. However every time we do that all users of the said APIs wake up one morning and they cannot login into their computer anymore. So this kind of workaround exist to prevent such events in return for some weird code and maintenance burden.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM