mirror of
https://github.com/Chatterino/chatterino2.git
synced 2026-08-24 10:04:53 -05:00
docs(plugins): Add more info on Windows, Splits, and SplitContainers (#6949)
From https://github.com/Chatterino/chatterino2/pull/6687#discussion_r3068317999, this adds more documentation on splits and so on. It also adds a utility to dump the layout to GraphViz which can be handy. Reviewed-by: Mm2PL <mm2pl+gh@kotmisia.pl> Reviewed-by: pajlada <rasmus.karlsson@pajlada.com> Parent-pr: 6687
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 7.8 KiB |
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 6.8 KiB |
@@ -0,0 +1,137 @@
|
||||
-- SPDX-FileCopyrightText: 2026 Contributors to Chatterino <https://chatterino.com>
|
||||
--
|
||||
-- SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
--[=[
|
||||
|
||||
Dumps the window tree in a Chatterino instance to GraphViz.
|
||||
|
||||
Usage: /windows
|
||||
|
||||
]=]
|
||||
--
|
||||
|
||||
local function enum_to_string(enum)
|
||||
local rev = {}
|
||||
for k, v in pairs(enum) do
|
||||
rev[v] = k
|
||||
end
|
||||
return function(v)
|
||||
local r = rev[v]
|
||||
if r ~= nil then
|
||||
return r
|
||||
end
|
||||
return "unknown-value(" .. v .. ")"
|
||||
end
|
||||
end
|
||||
local SPCNT_to_string = enum_to_string(c2.SplitContainerNodeType)
|
||||
local WindowType_to_string = enum_to_string(c2.WindowType)
|
||||
|
||||
--- Slightly changed version of 11.6 String Buffers: https://www.lua.org/pil/11.6.html
|
||||
local function new_strbuf()
|
||||
local s = { "" }
|
||||
---@param ... string
|
||||
function s:push(...)
|
||||
local size = #self
|
||||
for i, v in ipairs({ ... }) do
|
||||
self[size + i] = v
|
||||
end
|
||||
for i = #self - 1, 1, -1 do
|
||||
if string.len(self[i]) > string.len(self[i + 1]) then
|
||||
break
|
||||
end
|
||||
self[i] = self[i] .. table.remove(self)
|
||||
end
|
||||
end
|
||||
function s:flush()
|
||||
return table.concat(self)
|
||||
end
|
||||
return s
|
||||
end
|
||||
local outbuf = new_strbuf()
|
||||
|
||||
---@param s c2.Split|nil
|
||||
---@param id string
|
||||
local function do_split(s, id)
|
||||
if not s then
|
||||
outbuf:push(id, '[label="(nil)"]')
|
||||
return
|
||||
end
|
||||
outbuf:push(id, '[label="Split(channel=', s.channel:get_name(), ')"];\n')
|
||||
end
|
||||
|
||||
---@param p c2.SplitContainerNode|nil
|
||||
---@param id string
|
||||
local function do_node(p, id)
|
||||
if not p then
|
||||
outbuf:push(id, '[label="(nil)"]')
|
||||
return
|
||||
end
|
||||
|
||||
outbuf:push(
|
||||
id,
|
||||
'[label="SplitContainerNode(type=',
|
||||
SPCNT_to_string(p.type),
|
||||
", hflex=",
|
||||
string.format("%.2f", p.horizontal_flex),
|
||||
", vflex=",
|
||||
string.format("%.2f", p.vertical_flex),
|
||||
')"];\n'
|
||||
)
|
||||
if p.split then
|
||||
local sid = id .. "s"
|
||||
do_split(p.split, sid)
|
||||
outbuf:push(id, "->", sid, "\n")
|
||||
end
|
||||
for i, child in ipairs(p:children()) do
|
||||
local inner_id = id .. "c" .. i
|
||||
do_node(child, inner_id)
|
||||
outbuf:push(id, "->", inner_id, "\n")
|
||||
end
|
||||
end
|
||||
|
||||
---@param p c2.SplitContainer|nil
|
||||
---@param id string
|
||||
local function do_container(p, id)
|
||||
if not p then
|
||||
outbuf:push(id, '[label="(nil)"]')
|
||||
return
|
||||
end
|
||||
outbuf:push(id, '[label="SplitContainer"];\n')
|
||||
local base_id = id .. "b"
|
||||
do_node(p.base_node, base_id)
|
||||
outbuf:push(id, "->", base_id, "\n")
|
||||
end
|
||||
|
||||
---@param win c2.Window
|
||||
---@param id string
|
||||
local function do_window(win, id)
|
||||
outbuf:push(id, '[label="Window(type=', WindowType_to_string(win.type), ')"];\n')
|
||||
for i = 1, win.notebook.page_count do
|
||||
local inner_id = id .. "p" .. tostring(i)
|
||||
do_container(win.notebook:page_at(i - 1), inner_id)
|
||||
outbuf:push(id, "->", inner_id, "\n")
|
||||
end
|
||||
end
|
||||
|
||||
c2.register_command("/windows", function(ctx)
|
||||
outbuf = new_strbuf()
|
||||
outbuf:push("digraph {\nrankdir=TB;\nnode[shape=rect];\n")
|
||||
for i, win in ipairs(c2.windows:all()) do
|
||||
local id = "w" .. i
|
||||
do_window(win, id)
|
||||
end
|
||||
outbuf:push("}\n")
|
||||
local s = outbuf:flush()
|
||||
local msg = c2.Message.new({
|
||||
elements = {
|
||||
{
|
||||
type = "text",
|
||||
color = "link",
|
||||
link = { type = c2.LinkType.CopyToClipboard, value = s },
|
||||
text = "Copy",
|
||||
},
|
||||
},
|
||||
})
|
||||
ctx.channel:add_message(msg)
|
||||
end)
|
||||
+28
-5
@@ -897,12 +897,22 @@ Requires the [network permission](#permissions).
|
||||
|
||||
#### `Split`
|
||||
|
||||
A split. See [Anatomy of a Chatterino window](https://wiki.chatterino.com/Glossary/#anatomy-of-a-chatterino-window).
|
||||
This holds a `channel` ([Channel](#channel)) that's open in this split.
|
||||
A leaf node in the tab-tree of a Chatterino window.
|
||||
It shows a `channel` ([Channel](#channel)) along with a header and an input box.
|
||||
See [Anatomy of a Chatterino window](https://wiki.chatterino.com/Glossary/#anatomy-of-a-chatterino-window).
|
||||
|
||||
#### `SplitContainerNode`
|
||||
|
||||
A node in a split container. It has the following fields:
|
||||
A node in a split container.
|
||||
|
||||
It can be one of the following `type`s (`SplitContainerNodeType`):
|
||||
|
||||
- `EmptyRoot`: This is the only node in the `SplitContainer` and it's empty.
|
||||
- `Split`: This is a leaf node which holds a `split`.
|
||||
- `VerticalContainer`: The children of this node are arranged vertically. Each child's `vertical_flex` indicates how much space it takes.
|
||||
- `HorizontalContainer`: The children of this node are arranged horizontally. Each child's `horizontal_flex` indicates how much space it takes.
|
||||
|
||||
It has the following fields:
|
||||
|
||||
- `type` (`SplitContainerNodeType`) The type of this node
|
||||
- `split` ([`Split`](#split)?) The split contained in this code (if this is a split node)
|
||||
@@ -916,7 +926,8 @@ Get all children ([`SplitContainerNode`](#splitcontainernode)) of this node.
|
||||
|
||||
#### `SplitContainer`
|
||||
|
||||
A container with potentially multiple splits. It has the following fields:
|
||||
A container with potentially multiple splits each tab in Chatterino contains one `SplitContainer`.
|
||||
It has the following fields:
|
||||
|
||||
- `selected_split` ([`Split`](#split)) The currently selected split.
|
||||
- `base_node` ([`SplitContainerNode`](#splitcontainernode)) The top level node.
|
||||
@@ -927,6 +938,8 @@ Get all splits ([`Split`](#split)) contained in this container.
|
||||
|
||||
#### `SplitNotebook`
|
||||
|
||||
The tab bar in a Chatterino window. Each tab is called a "page" which holds a `SplitContainer`.
|
||||
|
||||
- `selected_page` ([`SplitContainer`](#splitcontainer)?) The currently selected page.
|
||||
- `page_count` (`integer`) The number of pages/tabs.
|
||||
|
||||
@@ -945,7 +958,17 @@ It has the following fields:
|
||||
|
||||
#### `WindowManager`
|
||||
|
||||
It has the following fields:
|
||||
Conceptually the windows in Chatterino are the root nodes of a tree with split containers as intermediate nodes and splits as leaf nodes.
|
||||
|
||||
[`docs/resources/window-graph.lua`](resources/window-graph.lua) is a utility to generate a GraphViz description of the window state.
|
||||
For example, the following tab is shown below:
|
||||
|
||||

|
||||
|
||||
GraphViz output:
|
||||

|
||||
|
||||
`WindowManager` has the following fields:
|
||||
|
||||
- `main_window` ([`Window`](#window)) The main window.
|
||||
- `last_selected_window` ([`Window`](#window)) The last selected window (or the main window if none were selected last).
|
||||
|
||||
Reference in New Issue
Block a user