summaryrefslogtreecommitdiff
path: root/docs/guide/lua/variable.md
blob: 915632cb0bfd9a11738a3f93a63299c80cb08a38 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
# Variable

```lua
local Variable = require("astal").Variable
local Variable = require("astal.variable")
```

Variable is just a simple object which holds a single value.
It also has some shortcuts for hooking up subprocesses, intervals and other gobjects.

## Example Usage

```lua
local my_var = Variable("initial-value")

-- whenever its value changes, callback will be executed
my_var:subscribe(function(value)
    print(value)
end)

-- settings its value
my_var:set("new value")

-- getting its value
local value = my_var:get()

-- binding them to widgets
Widget.Label({
    label = bind(my_var):as(function(value)
        return string.format("transformed %s", value)
    end),
    -- shorthand for the above
    label = my_var(function(value)
        return string.format("transformed %s", value)
    end)
})
```

:::warning
Make sure to the transform functions you pass to `:as()` are pure.
The `:get()` function can be called anytime by `astal` especially when `deriving`,
so make sure there are no sideeffects.
:::

## Variable Composition

Using `Variable.derive` any `Subscribable` object can be composed.

```lua
local v1 = Variable(1) -- Variable
local v2 = bind(obj, "prop") -- Binding
local v3 = { -- Subscribable
    get = function()
        return 3
    end,
    subscribe = function()
        return function() end
    end,
}

-- first argument is a list of dependencies
-- second argument is a transform function,
-- where the parameters are the values of the dependencies in the order they were passed
local v4 = Variable.derive({ v1, v2, v3 }, function(v1, v2, v3)
    return v1 * v2 * v3
end)
```

## Subprocess shorthands

Using `:poll` and `:watch` you can start subprocesses and capture their
output. They can poll and watch at the same time, but they
can only poll/watch once.

:::warning
The command parameter is passed to [exec_async](/guide/lua/utilities#executing-external-commands-and-scripts)
which means they are **not** executed in a shell environment,
they do **not** expand ENV variables like `$HOME`,
and they do **not** handle logical operators like `&&` and `||`.

If you want bash, run them with bash.

```lua
Variable(""):poll(1000, { "bash", "-c", "command $VAR && command" })
```

:::

```lua
local my_var = Variable(0)
    :poll(1000, "command", function(out, prev)
        return tonumber(out)
    end)
    :poll(1000, { "bash", "-c", "command" }, function(out, prev)
        return tonumber(out)
    end)
    :poll(1000, function(prev)
        return prev + 1
    end)
```

```lua
local my_var = Variable(0)
    :watch("command", function(out, prev)
        return tonumber(out)
    end)
    :watch({ "bash", "-c", "command" }, function(out, prev)
        return tonumber(out)
    end)
```

You can temporarily stop them and restart them whenever.

```lua
my_var:stop_watch() -- this kills the subprocess
my_var:stop_poll()

my_var:start_listen() -- launches the subprocess again
my_var:start_poll()

print(my_var:is_listening())
print(my_var:is_polling())
```

## Gobject connection shorthands

Using `:observe` you can connect gobject signals and capture their value.

```lua
local my_var = Variable("")
    :observe(obj1, "signal", function()
        return ""
    end):observe(obj2, "signal", function()
        return ""
    end)
```

## Dispose if no longer needed

This will stop the interval, force exit the subprocess and disconnect gobjects.

```lua
my_var:drop()
```

:::warning
Don't forget to drop derived variables or variables with
either `:poll`, `:watch` or `:observe` when they are defined inside closures.

```lua
local function MyWidget()
    local my_var = Variable():poll()

    return Widget.Box({
        on_destroy = function()
            my_var:drop()
        end
    })
end
```

:::