WIP: awesomerc.tl
should work #85
|
@ -1,4 +1,6 @@
|
|||
lua_modules/
|
||||
generated/
|
||||
generated/*
|
||||
!generated/awesomerc.tl
|
||||
!generated/tlconfig.lua
|
||||
build/
|
||||
luacov/
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
},
|
||||
"args": [
|
||||
"test",
|
||||
"_spec" // Adapt to the spec to debug
|
||||
"\"--pattern _spec --tags debug\""
|
||||
],
|
||||
"scriptFiles": ["${workspaceFolder}/**/*.tl"]
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
"aireone",
|
||||
"akorn",
|
||||
"ansicolors",
|
||||
"awesomerc",
|
||||
"awesomewm",
|
||||
"awesomewmdtl",
|
||||
"buildx",
|
||||
|
@ -31,6 +32,7 @@
|
|||
"Luarocks",
|
||||
"luasec",
|
||||
"luasocket",
|
||||
"metamethods",
|
||||
"mkdir",
|
||||
"modname",
|
||||
"reportfile",
|
||||
|
@ -45,6 +47,7 @@
|
|||
"sublist",
|
||||
"tablex",
|
||||
"tbody",
|
||||
"tlconfig",
|
||||
"tmpl",
|
||||
"wibox",
|
||||
"woodpeckerci",
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
variables:
|
||||
- &cyan gitea.aireone.xyz/aire-one/awesomewm.d.tl/cyan:latest
|
||||
|
||||
pipeline:
|
||||
build-and-run:
|
||||
image: *cyan
|
||||
commands:
|
||||
- luarocks make awesomewmdtl-dev-1.rockspec
|
||||
- awesomewmdtl
|
||||
- just validate
|
||||
|
||||
branches: master
|
||||
|
||||
depends_on:
|
||||
- docker-build
|
|
@ -1,23 +0,0 @@
|
|||
variables:
|
||||
- &cyan gitea.aireone.xyz/aire-one/awesomewm.d.tl/cyan:latest
|
||||
|
||||
pipeline:
|
||||
build:
|
||||
image: *cyan
|
||||
commands:
|
||||
- just build
|
||||
# run:
|
||||
# image: akorn/luarocks:lua5.4-alpine
|
||||
# commands:
|
||||
# - apk add just
|
||||
# - just run
|
||||
# verify:
|
||||
# image: alpine:3.16
|
||||
# commands:
|
||||
# - apk add tree
|
||||
# - tree generated
|
||||
|
||||
branches: master
|
||||
|
||||
depends_on:
|
||||
- docker-build
|
|
@ -57,6 +57,7 @@ build = {
|
|||
["awesomewmdtl.types.Dag"] = "build/awesomewmdtl/types/Dag.lua",
|
||||
["awesomewmdtl.types.Node"] = "build/awesomewmdtl/types/Node.lua",
|
||||
["awesomewmdtl.visitors.module_dependencies"] = "build/awesomewmdtl/visitors/module_dependencies.lua",
|
||||
["awesomewmdtl.visitors.node_fixer"] = "build/awesomewmdtl/visitors/node_fixer.lua",
|
||||
["awesomewmdtl.visitors.type_mapping"] = "build/awesomewmdtl/visitors/type_mapping.lua",
|
||||
["awesomewmdtl.ast"] = "build/awesomewmdtl/ast.lua",
|
||||
["awesomewmdtl.dag"] = "build/awesomewmdtl/dag.lua",
|
||||
|
|
|
@ -0,0 +1,675 @@
|
|||
-- awesome_mode: api-level=4:screen=on
|
||||
-- If LuaRocks is installed, make sure that packages installed through it are
|
||||
-- found (e.g. lgi). If LuaRocks is not installed, do nothing.
|
||||
--- TODO : Write luarocks basic types definitions
|
||||
-- pcall(require, "luarocks.loader")
|
||||
|
||||
-- @DOC_REQUIRE_SECTION@
|
||||
-- Standard awesome library
|
||||
local gears = require("gears")
|
||||
local awful = require("awful")
|
||||
require("awful.autofocus")
|
||||
-- Widget and layout library
|
||||
local wibox = require("wibox")
|
||||
-- Theme handling library
|
||||
local beautiful = require("beautiful")
|
||||
-- Notification library
|
||||
local naughty = require("naughty")
|
||||
-- Declarative object management
|
||||
local ruled = require("ruled")
|
||||
local menubar = require("menubar")
|
||||
local hotkeys_popup = require("awful.hotkeys_popup")
|
||||
-- Enable hotkeys help widget for VIM and other apps
|
||||
-- when client with a matching name is opened:
|
||||
require("awful.hotkeys_popup.keys")
|
||||
|
||||
-- {{{ Error handling
|
||||
-- Check if awesome encountered an error during startup and fell back to
|
||||
-- another config (This code will only ever execute for the fallback config)
|
||||
-- @DOC_ERROR_HANDLING@
|
||||
naughty.connect_signal("request::display_error", function(message, startup)
|
||||
naughty.notification {
|
||||
urgency = "critical",
|
||||
title = "Oops, an error happened"
|
||||
.. (startup and " during startup!" or "!"),
|
||||
message = message,
|
||||
}
|
||||
end)
|
||||
-- }}}
|
||||
|
||||
-- {{{ Variable definitions
|
||||
-- @DOC_LOAD_THEME@
|
||||
-- Themes define colours, icons, font and wallpapers.
|
||||
beautiful.init(gears.filesystem.get_themes_dir() .. "default/theme.lua")
|
||||
|
||||
-- @DOC_DEFAULT_APPLICATIONS@
|
||||
-- This is used later as the default terminal and editor to run.
|
||||
local terminal = "xterm"
|
||||
local editor = os.getenv "EDITOR" or "nano"
|
||||
local editor_cmd = terminal .. " -e " .. editor
|
||||
|
||||
-- Default modkey.
|
||||
-- Usually, Mod4 is the key with a logo between Control and Alt.
|
||||
-- If you do not like this or do not have such a key,
|
||||
-- I suggest you to remap Mod4 to another key using xmodmap or other tools.
|
||||
-- However, you can use another modifier like Mod1, but it may interact with others.
|
||||
local modkey = "Mod4"
|
||||
-- }}}
|
||||
|
||||
-- {{{ Menu
|
||||
-- @DOC_MENU@
|
||||
-- Create a launcher widget and a main menu
|
||||
local myawesomemenu = {
|
||||
{
|
||||
"hotkeys",
|
||||
function()
|
||||
hotkeys_popup.show_help(nil, awful.screen.focused())
|
||||
end,
|
||||
},
|
||||
{ "manual", terminal .. " -e man awesome" },
|
||||
{ "edit config", editor_cmd .. " " .. awesome.conffile },
|
||||
{ "restart", awesome.restart },
|
||||
{
|
||||
"quit",
|
||||
function()
|
||||
awesome.quit()
|
||||
end,
|
||||
},
|
||||
}
|
||||
|
||||
local mymainmenu = awful.menu {
|
||||
items = {
|
||||
{ "awesome", myawesomemenu, beautiful.awesome_icon },
|
||||
{ "open terminal", terminal },
|
||||
},
|
||||
}
|
||||
|
||||
local mylauncher = awful.widget.launcher {
|
||||
image = beautiful.awesome_icon,
|
||||
menu = mymainmenu,
|
||||
}
|
||||
|
||||
-- Menubar configuration
|
||||
menubar.utils.terminal = terminal -- Set the terminal for applications that require it
|
||||
-- }}}
|
||||
|
||||
-- {{{ Tag layout
|
||||
-- @DOC_LAYOUT@
|
||||
-- Table of layouts to cover with awful.layout.inc, order matters.
|
||||
tag.connect_signal("request::default_layouts", function()
|
||||
awful.layout.append_default_layouts {
|
||||
awful.layout.suit.floating,
|
||||
awful.layout.suit.tile,
|
||||
awful.layout.suit.tile.left,
|
||||
awful.layout.suit.tile.bottom,
|
||||
awful.layout.suit.tile.top,
|
||||
awful.layout.suit.fair,
|
||||
awful.layout.suit.fair.horizontal,
|
||||
awful.layout.suit.spiral,
|
||||
awful.layout.suit.spiral.dwindle,
|
||||
awful.layout.suit.max,
|
||||
awful.layout.suit.max.fullscreen,
|
||||
awful.layout.suit.magnifier,
|
||||
awful.layout.suit.corner.nw,
|
||||
}
|
||||
end)
|
||||
-- }}}
|
||||
|
||||
-- {{{ Wallpaper
|
||||
-- @DOC_WALLPAPER@
|
||||
screen.connect_signal("request::wallpaper", function(s)
|
||||
awful.wallpaper {
|
||||
screen = s,
|
||||
widget = {
|
||||
{
|
||||
image = beautiful.wallpaper,
|
||||
upscale = true,
|
||||
downscale = true,
|
||||
widget = wibox.widget.imagebox,
|
||||
},
|
||||
valign = "center",
|
||||
halign = "center",
|
||||
tiled = false,
|
||||
widget = wibox.container.tile,
|
||||
},
|
||||
}
|
||||
end)
|
||||
-- }}}
|
||||
|
||||
-- {{{ Wibar
|
||||
|
||||
-- Keyboard map indicator and switcher
|
||||
local mykeyboardlayout = awful.widget.keyboardlayout()
|
||||
|
||||
-- Create a textclock widget
|
||||
local mytextclock = wibox.widget.textclock()
|
||||
|
||||
-- @DOC_FOR_EACH_SCREEN@
|
||||
screen.connect_signal("request::desktop_decoration", function(s: screen)
|
||||
-- Each screen has its own tag table.
|
||||
awful.tag(
|
||||
{ "1", "2", "3", "4", "5", "6", "7", "8", "9" },
|
||||
s,
|
||||
awful.layout.layouts[1]
|
||||
)
|
||||
|
||||
-- Create a promptbox for each screen
|
||||
s.mypromptbox = awful.widget.prompt()
|
||||
|
||||
-- Create an imagebox widget which will contain an icon indicating which layout we're using.
|
||||
-- We need one layoutbox per screen.
|
||||
s.mylayoutbox = awful.widget.layoutbox {
|
||||
screen = s,
|
||||
buttons = {
|
||||
awful.button({}, 1, function()
|
||||
awful.layout.inc(1)
|
||||
end),
|
||||
awful.button({}, 3, function()
|
||||
awful.layout.inc(-1)
|
||||
end),
|
||||
awful.button({}, 4, function()
|
||||
awful.layout.inc(-1)
|
||||
end),
|
||||
awful.button({}, 5, function()
|
||||
awful.layout.inc(1)
|
||||
end),
|
||||
},
|
||||
}
|
||||
|
||||
-- Create a taglist widget
|
||||
s.mytaglist = awful.widget.taglist {
|
||||
screen = s,
|
||||
filter = awful.widget.taglist.filter.all,
|
||||
buttons = {
|
||||
awful.button({}, 1, function(t: tag)
|
||||
t:view_only()
|
||||
end),
|
||||
awful.button({ modkey }, 1, function(t: tag)
|
||||
if client.focus then
|
||||
client.focus:move_to_tag(t)
|
||||
end
|
||||
end),
|
||||
awful.button({}, 3, awful.tag.viewtoggle),
|
||||
awful.button({ modkey }, 3, function(t: tag)
|
||||
if client.focus then
|
||||
client.focus:toggle_tag(t)
|
||||
end
|
||||
end),
|
||||
awful.button({}, 4, function(t: tag)
|
||||
awful.tag.viewprev(t.screen)
|
||||
end),
|
||||
awful.button({}, 5, function(t: tag)
|
||||
awful.tag.viewnext(t.screen)
|
||||
end),
|
||||
},
|
||||
}
|
||||
|
||||
-- @TASKLIST_BUTTON@
|
||||
-- Create a tasklist widget
|
||||
s.mytasklist = awful.widget.tasklist {
|
||||
screen = s,
|
||||
filter = awful.widget.tasklist.filter.currenttags,
|
||||
buttons = {
|
||||
awful.button({}, 1, function(c)
|
||||
c:activate { context = "tasklist", action = "toggle_minimization" }
|
||||
end),
|
||||
awful.button({}, 3, function()
|
||||
awful.menu.client_list { theme = { width = 250 } }
|
||||
end),
|
||||
awful.button({}, 4, function()
|
||||
awful.client.focus.byidx(-1)
|
||||
end),
|
||||
awful.button({}, 5, function()
|
||||
awful.client.focus.byidx(1)
|
||||
end),
|
||||
},
|
||||
}
|
||||
|
||||
-- @DOC_WIBAR@
|
||||
-- Create the wibox
|
||||
s.mywibox = awful.wibar {
|
||||
position = "top",
|
||||
screen = s,
|
||||
-- @DOC_SETUP_WIDGETS@
|
||||
widget = {
|
||||
layout = wibox.layout.align.horizontal,
|
||||
{ -- Left widgets
|
||||
layout = wibox.layout.fixed.horizontal,
|
||||
mylauncher,
|
||||
s.mytaglist,
|
||||
s.mypromptbox,
|
||||
},
|
||||
s.mytasklist, -- Middle widget
|
||||
{ -- Right widgets
|
||||
layout = wibox.layout.fixed.horizontal,
|
||||
mykeyboardlayout,
|
||||
wibox.widget.systray(),
|
||||
mytextclock,
|
||||
s.mylayoutbox,
|
||||
},
|
||||
},
|
||||
}
|
||||
end)
|
||||
|
||||
-- }}}
|
||||
|
||||
-- {{{ Mouse bindings
|
||||
-- @DOC_ROOT_BUTTONS@
|
||||
awful.mouse.append_global_mousebindings {
|
||||
awful.button({}, 3, function()
|
||||
mymainmenu:toggle()
|
||||
end),
|
||||
awful.button({}, 4, awful.tag.viewprev),
|
||||
awful.button({}, 5, awful.tag.viewnext),
|
||||
}
|
||||
-- }}}
|
||||
|
||||
-- {{{ Key bindings
|
||||
-- @DOC_GLOBAL_KEYBINDINGS@
|
||||
|
||||
-- General Awesome keys
|
||||
awful.keyboard.append_global_keybindings {
|
||||
awful.key(
|
||||
{ modkey },
|
||||
"s",
|
||||
hotkeys_popup.show_help,
|
||||
{ description = "show help", group = "awesome" }
|
||||
),
|
||||
awful.key({ modkey }, "w", function()
|
||||
mymainmenu:show()
|
||||
end, { description = "show main menu", group = "awesome" }),
|
||||
awful.key(
|
||||
{ modkey, "Control" },
|
||||
"r",
|
||||
awesome.restart,
|
||||
{ description = "reload awesome", group = "awesome" }
|
||||
),
|
||||
awful.key(
|
||||
{ modkey, "Shift" },
|
||||
"q",
|
||||
awesome.quit,
|
||||
{ description = "quit awesome", group = "awesome" }
|
||||
),
|
||||
awful.key({ modkey }, "x", function()
|
||||
awful.prompt.run {
|
||||
prompt = "Run Lua code: ",
|
||||
textbox = awful.screen.focused().mypromptbox.widget,
|
||||
exe_callback = awful.util.eval,
|
||||
history_path = awful.util.get_cache_dir() .. "/history_eval",
|
||||
}
|
||||
end, { description = "lua execute prompt", group = "awesome" }),
|
||||
awful.key({ modkey }, "Return", function()
|
||||
awful.spawn(terminal)
|
||||
end, { description = "open a terminal", group = "launcher" }),
|
||||
awful.key({ modkey }, "r", function()
|
||||
awful.screen.focused().mypromptbox:run()
|
||||
end, { description = "run prompt", group = "launcher" }),
|
||||
awful.key({ modkey }, "p", function()
|
||||
menubar.show()
|
||||
end, { description = "show the menubar", group = "launcher" }),
|
||||
}
|
||||
|
||||
-- Tags related keybindings
|
||||
awful.keyboard.append_global_keybindings {
|
||||
awful.key(
|
||||
{ modkey },
|
||||
"Left",
|
||||
awful.tag.viewprev,
|
||||
{ description = "view previous", group = "tag" }
|
||||
),
|
||||
awful.key(
|
||||
{ modkey },
|
||||
"Right",
|
||||
awful.tag.viewnext,
|
||||
{ description = "view next", group = "tag" }
|
||||
),
|
||||
awful.key(
|
||||
{ modkey },
|
||||
"Escape",
|
||||
awful.tag.history.restore,
|
||||
{ description = "go back", group = "tag" }
|
||||
),
|
||||
}
|
||||
|
||||
-- Focus related keybindings
|
||||
awful.keyboard.append_global_keybindings {
|
||||
awful.key({ modkey }, "j", function()
|
||||
awful.client.focus.byidx(1)
|
||||
end, { description = "focus next by index", group = "client" }),
|
||||
awful.key({ modkey }, "k", function()
|
||||
awful.client.focus.byidx(-1)
|
||||
end, { description = "focus previous by index", group = "client" }),
|
||||
awful.key({ modkey }, "Tab", function()
|
||||
awful.client.focus.history.previous()
|
||||
if client.focus then
|
||||
client.focus:raise()
|
||||
end
|
||||
end, { description = "go back", group = "client" }),
|
||||
awful.key({ modkey, "Control" }, "j", function()
|
||||
awful.screen.focus_relative(1)
|
||||
end, { description = "focus the next screen", group = "screen" }),
|
||||
awful.key({ modkey, "Control" }, "k", function()
|
||||
awful.screen.focus_relative(-1)
|
||||
end, { description = "focus the previous screen", group = "screen" }),
|
||||
awful.key({ modkey, "Control" }, "n", function()
|
||||
local c = awful.client.restore()
|
||||
-- Focus restored client
|
||||
if c then
|
||||
c:activate { raise = true, context = "key.unminimize" }
|
||||
end
|
||||
end, { description = "restore minimized", group = "client" }),
|
||||
}
|
||||
|
||||
-- Layout related keybindings
|
||||
awful.keyboard.append_global_keybindings {
|
||||
awful.key({ modkey, "Shift" }, "j", function()
|
||||
awful.client.swap.byidx(1)
|
||||
end, { description = "swap with next client by index", group = "client" }),
|
||||
awful.key(
|
||||
{ modkey, "Shift" },
|
||||
"k",
|
||||
function()
|
||||
awful.client.swap.byidx(-1)
|
||||
end,
|
||||
{ description = "swap with previous client by index", group = "client" }
|
||||
),
|
||||
awful.key(
|
||||
{ modkey },
|
||||
"u",
|
||||
awful.client.urgent.jumpto,
|
||||
{ description = "jump to urgent client", group = "client" }
|
||||
),
|
||||
awful.key({ modkey }, "l", function()
|
||||
awful.tag.incmwfact(0.05)
|
||||
end, { description = "increase master width factor", group = "layout" }),
|
||||
awful.key({ modkey }, "h", function()
|
||||
awful.tag.incmwfact(-0.05)
|
||||
end, { description = "decrease master width factor", group = "layout" }),
|
||||
awful.key({ modkey, "Shift" }, "h", function()
|
||||
awful.tag.incnmaster(1, nil, true)
|
||||
end, {
|
||||
description = "increase the number of master clients",
|
||||
group = "layout",
|
||||
}),
|
||||
awful.key({ modkey, "Shift" }, "l", function()
|
||||
awful.tag.incnmaster(-1, nil, true)
|
||||
end, {
|
||||
description = "decrease the number of master clients",
|
||||
group = "layout",
|
||||
}),
|
||||
awful.key({ modkey, "Control" }, "h", function()
|
||||
awful.tag.incncol(1, nil, true)
|
||||
end, { description = "increase the number of columns", group = "layout" }),
|
||||
awful.key({ modkey, "Control" }, "l", function()
|
||||
awful.tag.incncol(-1, nil, true)
|
||||
end, { description = "decrease the number of columns", group = "layout" }),
|
||||
awful.key({ modkey }, "space", function()
|
||||
awful.layout.inc(1)
|
||||
end, { description = "select next", group = "layout" }),
|
||||
awful.key({ modkey, "Shift" }, "space", function()
|
||||
awful.layout.inc(-1)
|
||||
end, { description = "select previous", group = "layout" }),
|
||||
}
|
||||
|
||||
-- @DOC_NUMBER_KEYBINDINGS@
|
||||
|
||||
awful.keyboard.append_global_keybindings {
|
||||
awful.key {
|
||||
modifiers = { modkey },
|
||||
keygroup = "numrow",
|
||||
description = "only view tag",
|
||||
group = "tag",
|
||||
on_press = function(index)
|
||||
local screen = awful.screen.focused()
|
||||
local tag = screen.tags[index]
|
||||
if tag then
|
||||
tag:view_only()
|
||||
end
|
||||
end,
|
||||
},
|
||||
awful.key {
|
||||
modifiers = { modkey, "Control" },
|
||||
keygroup = "numrow",
|
||||
description = "toggle tag",
|
||||
group = "tag",
|
||||
on_press = function(index)
|
||||
local screen = awful.screen.focused()
|
||||
local tag = screen.tags[index]
|
||||
if tag then
|
||||
awful.tag.viewtoggle(tag)
|
||||
end
|
||||
end,
|
||||
},
|
||||
awful.key {
|
||||
modifiers = { modkey, "Shift" },
|
||||
keygroup = "numrow",
|
||||
description = "move focused client to tag",
|
||||
group = "tag",
|
||||
on_press = function(index)
|
||||
if client.focus then
|
||||
local tag = client.focus.screen.tags[index]
|
||||
if tag then
|
||||
client.focus:move_to_tag(tag)
|
||||
end
|
||||
end
|
||||
end,
|
||||
},
|
||||
awful.key {
|
||||
modifiers = { modkey, "Control", "Shift" },
|
||||
keygroup = "numrow",
|
||||
description = "toggle focused client on tag",
|
||||
group = "tag",
|
||||
on_press = function(index)
|
||||
if client.focus then
|
||||
local tag = client.focus.screen.tags[index]
|
||||
if tag then
|
||||
client.focus:toggle_tag(tag)
|
||||
end
|
||||
end
|
||||
end,
|
||||
},
|
||||
awful.key {
|
||||
modifiers = { modkey },
|
||||
keygroup = "numpad",
|
||||
description = "select layout directly",
|
||||
group = "layout",
|
||||
on_press = function(index)
|
||||
local t = awful.screen.focused().selected_tag
|
||||
if t then
|
||||
t.layout = t.layouts[index] or t.layout
|
||||
end
|
||||
end,
|
||||
},
|
||||
}
|
||||
|
||||
-- @DOC_CLIENT_BUTTONS@
|
||||
client.connect_signal("request::default_mousebindings", function()
|
||||
awful.mouse.append_client_mousebindings {
|
||||
awful.button({}, 1, function(c)
|
||||
c:activate { context = "mouse_click" }
|
||||
end),
|
||||
awful.button({ modkey }, 1, function(c)
|
||||
c:activate { context = "mouse_click", action = "mouse_move" }
|
||||
end),
|
||||
awful.button({ modkey }, 3, function(c)
|
||||
c:activate { context = "mouse_click", action = "mouse_resize" }
|
||||
end),
|
||||
}
|
||||
end)
|
||||
|
||||
-- @DOC_CLIENT_KEYBINDINGS@
|
||||
client.connect_signal("request::default_keybindings", function()
|
||||
awful.keyboard.append_client_keybindings {
|
||||
awful.key({ modkey }, "f", function(c: client)
|
||||
c.fullscreen = not c.fullscreen
|
||||
c:raise()
|
||||
end, { description = "toggle fullscreen", group = "client" }),
|
||||
awful.key({ modkey, "Shift" }, "c", function(c: client)
|
||||
c:kill()
|
||||
end, { description = "close", group = "client" }),
|
||||
awful.key(
|
||||
{ modkey, "Control" },
|
||||
"space",
|
||||
awful.client.floating.toggle,
|
||||
{ description = "toggle floating", group = "client" }
|
||||
),
|
||||
awful.key({ modkey, "Control" }, "Return", function(c: client)
|
||||
c:swap(awful.client.getmaster())
|
||||
end, { description = "move to master", group = "client" }),
|
||||
awful.key({ modkey }, "o", function(c: client)
|
||||
c:move_to_screen()
|
||||
end, { description = "move to screen", group = "client" }),
|
||||
awful.key({ modkey }, "t", function(c: client)
|
||||
c.ontop = not c.ontop
|
||||
end, { description = "toggle keep on top", group = "client" }),
|
||||
awful.key({ modkey }, "n", function(c: client)
|
||||
-- The client currently has the input focus, so it cannot be
|
||||
-- minimized, since minimized clients can't have the focus.
|
||||
c.minimized = true
|
||||
end, { description = "minimize", group = "client" }),
|
||||
awful.key({ modkey }, "m", function(c: client)
|
||||
c.maximized = not c.maximized
|
||||
c:raise()
|
||||
end, { description = "(un)maximize", group = "client" }),
|
||||
awful.key({ modkey, "Control" }, "m", function(c: client)
|
||||
c.maximized_vertical = not c.maximized_vertical
|
||||
c:raise()
|
||||
end, { description = "(un)maximize vertically", group = "client" }),
|
||||
awful.key({ modkey, "Shift" }, "m", function(c: client)
|
||||
c.maximized_horizontal = not c.maximized_horizontal
|
||||
c:raise()
|
||||
end, { description = "(un)maximize horizontally", group = "client" }),
|
||||
}
|
||||
end)
|
||||
|
||||
-- }}}
|
||||
|
||||
-- {{{ Rules
|
||||
-- Rules to apply to new clients.
|
||||
-- @DOC_RULES@
|
||||
ruled.client.connect_signal("request::rules", function()
|
||||
-- @DOC_GLOBAL_RULE@
|
||||
-- All clients will match this rule.
|
||||
ruled.client.append_rule {
|
||||
id = "global",
|
||||
rule = {},
|
||||
properties = {
|
||||
focus = awful.client.focus.filter,
|
||||
raise = true,
|
||||
screen = awful.screen.preferred,
|
||||
placement = awful.placement.no_overlap + awful.placement.no_offscreen,
|
||||
},
|
||||
}
|
||||
|
||||
-- @DOC_FLOATING_RULE@
|
||||
-- Floating clients.
|
||||
ruled.client.append_rule {
|
||||
id = "floating",
|
||||
rule_any = {
|
||||
instance = { "copyq", "pinentry" },
|
||||
class = {
|
||||
"Arandr",
|
||||
"Blueman-manager",
|
||||
"Gpick",
|
||||
"Kruler",
|
||||
"Sxiv",
|
||||
"Tor Browser",
|
||||
"Wpa_gui",
|
||||
"veromix",
|
||||
"xtightvncviewer",
|
||||
},
|
||||
-- Note that the name property shown in xprop might be set slightly after creation of the client
|
||||
-- and the name shown there might not match defined rules here.
|
||||
name = {
|
||||
"Event Tester", -- xev.
|
||||
},
|
||||
role = {
|
||||
"AlarmWindow", -- Thunderbird's calendar.
|
||||
"ConfigManager", -- Thunderbird's about:config.
|
||||
"pop-up", -- e.g. Google Chrome's (detached) Developer Tools.
|
||||
},
|
||||
},
|
||||
properties = { floating = true },
|
||||
}
|
||||
|
||||
-- @DOC_DIALOG_RULE@
|
||||
-- Add titlebars to normal clients and dialogs
|
||||
ruled.client.append_rule {
|
||||
-- @DOC_CSD_TITLEBARS@
|
||||
id = "titlebars",
|
||||
rule_any = { type = { "normal", "dialog" } },
|
||||
properties = { titlebars_enabled = true },
|
||||
}
|
||||
|
||||
-- Set Firefox to always map on the tag named "2" on screen 1.
|
||||
-- ruled.client.append_rule {
|
||||
-- rule = { class = "Firefox" },
|
||||
-- properties = { screen = 1, tag = "2" }
|
||||
-- }
|
||||
end)
|
||||
-- }}}
|
||||
|
||||
-- {{{ Titlebars
|
||||
-- @DOC_TITLEBARS@
|
||||
-- Add a titlebar if titlebars_enabled is set to true in the rules.
|
||||
client.connect_signal("request::titlebars", function(c: client)
|
||||
-- buttons for the titlebar
|
||||
local buttons = {
|
||||
awful.button({}, 1, function()
|
||||
c:activate { context = "titlebar", action = "mouse_move" }
|
||||
end),
|
||||
awful.button({}, 3, function()
|
||||
c:activate { context = "titlebar", action = "mouse_resize" }
|
||||
end),
|
||||
}
|
||||
|
||||
awful.titlebar(c).widget = {
|
||||
{ -- Left
|
||||
awful.titlebar.widget.iconwidget(c),
|
||||
buttons = buttons,
|
||||
layout = wibox.layout.fixed.horizontal,
|
||||
},
|
||||
{ -- Middle
|
||||
{ -- Title
|
||||
halign = "center",
|
||||
widget = awful.titlebar.widget.titlewidget(c),
|
||||
},
|
||||
buttons = buttons,
|
||||
layout = wibox.layout.flex.horizontal,
|
||||
},
|
||||
{ -- Right
|
||||
awful.titlebar.widget.floatingbutton(c),
|
||||
awful.titlebar.widget.maximizedbutton(c),
|
||||
awful.titlebar.widget.stickybutton(c),
|
||||
awful.titlebar.widget.ontopbutton(c),
|
||||
awful.titlebar.widget.closebutton(c),
|
||||
layout = wibox.layout.fixed.horizontal(),
|
||||
},
|
||||
layout = wibox.layout.align.horizontal,
|
||||
}
|
||||
end)
|
||||
-- }}}
|
||||
|
||||
-- {{{ Notifications
|
||||
|
||||
ruled.notification.connect_signal("request::rules", function()
|
||||
-- All notifications will match this rule.
|
||||
ruled.notification.append_rule {
|
||||
rule = {},
|
||||
properties = {
|
||||
screen = awful.screen.preferred,
|
||||
implicit_timeout = 5,
|
||||
},
|
||||
}
|
||||
end)
|
||||
|
||||
naughty.connect_signal("request::display", function(n)
|
||||
naughty.layout.box { notification = n }
|
||||
end)
|
||||
|
||||
-- }}}
|
||||
|
||||
-- Enable sloppy focus, so that focus follows mouse.
|
||||
client.connect_signal("mouse::enter", function(c: client)
|
||||
c:activate { context = "mouse_enter", raise = false }
|
||||
end)
|
|
@ -0,0 +1,4 @@
|
|||
return {
|
||||
source_dir = ".",
|
||||
global_env_def = "global_env_def",
|
||||
}
|
6
justfile
6
justfile
|
@ -62,16 +62,14 @@ run:
|
|||
validate:
|
||||
cd generated && cyan \
|
||||
check \
|
||||
--global-env-def "global_env" \
|
||||
awesomerc.tl
|
||||
# `find . -type f -iname '*.d.tl' | xargs`
|
||||
|
||||
test PATTERN="_spec":
|
||||
test PARAMETERS="--pattern=_spec":
|
||||
luarocks \
|
||||
--lua-version {{ lua_version }} \
|
||||
test \
|
||||
{{ rockspec_file }} \
|
||||
-- --pattern={{ PATTERN }}
|
||||
-- {{ PARAMETERS }}
|
||||
|
||||
local-test PATTERN="_spec":
|
||||
luarocks \
|
||||
|
|
|
@ -22,6 +22,7 @@ describe("Teal type definition Printer", function()
|
|||
{
|
||||
children = {},
|
||||
dependencies = {},
|
||||
descendants = {},
|
||||
name = "Empty",
|
||||
token = "module",
|
||||
},
|
||||
|
@ -53,6 +54,7 @@ describe("Teal type definition Printer", function()
|
|||
},
|
||||
},
|
||||
dependencies = {},
|
||||
descendants = {},
|
||||
name = "Signal_Module",
|
||||
token = "module",
|
||||
},
|
||||
|
@ -79,6 +81,7 @@ describe("Teal type definition Printer", function()
|
|||
}
|
||||
},
|
||||
dependencies = {},
|
||||
descendants = {},
|
||||
name = "Property_Module",
|
||||
token = "module",
|
||||
},
|
||||
|
@ -108,12 +111,13 @@ describe("Teal type definition Printer", function()
|
|||
token = "variable",
|
||||
},
|
||||
},
|
||||
return_types = { "boolean" },
|
||||
return_types = { { "boolean" }, { "nil", "number" } },
|
||||
name = "kill",
|
||||
token = "function",
|
||||
},
|
||||
},
|
||||
dependencies = {},
|
||||
descendants = {},
|
||||
name = "Function_Module",
|
||||
token = "module",
|
||||
},
|
||||
|
@ -121,7 +125,7 @@ describe("Teal type definition Printer", function()
|
|||
-- This file was auto-generated.
|
||||
|
||||
local record Function_Module
|
||||
kill: function(pid: integer, sig: integer): boolean
|
||||
kill: function(pid: integer, sig: integer): boolean, nil | number
|
||||
end
|
||||
|
||||
return Function_Module
|
||||
|
@ -137,6 +141,7 @@ describe("Teal type definition Printer", function()
|
|||
}
|
||||
},
|
||||
dependencies = {},
|
||||
descendants = {},
|
||||
name = "Nested_Module",
|
||||
token = "module",
|
||||
},
|
||||
|
@ -158,6 +163,7 @@ describe("Teal type definition Printer", function()
|
|||
dep = "dep",
|
||||
deeper = "path.dep.deeper",
|
||||
},
|
||||
descendants = {},
|
||||
name = "Module",
|
||||
token = "module",
|
||||
},
|
||||
|
@ -171,4 +177,104 @@ describe("Teal type definition Printer", function()
|
|||
|
||||
return Module
|
||||
]]))
|
||||
|
||||
it("should print __call metamethod", gen(
|
||||
{
|
||||
children = {
|
||||
{
|
||||
children = {},
|
||||
name = "Signal",
|
||||
token = "enum",
|
||||
},
|
||||
{
|
||||
parameters = {
|
||||
{
|
||||
types = { "Timer" },
|
||||
name = "self",
|
||||
token = "variable",
|
||||
},
|
||||
},
|
||||
return_types = {},
|
||||
name = "timer",
|
||||
metamethod = "__call",
|
||||
token = "metamethod",
|
||||
}
|
||||
},
|
||||
name = "Timer",
|
||||
module_path = "gears.timer",
|
||||
dependencies = {},
|
||||
descendants = {},
|
||||
global = false,
|
||||
token = "module",
|
||||
},
|
||||
[[
|
||||
-- This file was auto-generated.
|
||||
|
||||
local record Timer
|
||||
enum Signal
|
||||
end
|
||||
metamethod __call: function(self: Timer)
|
||||
end
|
||||
|
||||
return Timer
|
||||
]]))
|
||||
|
||||
it("should print a module with descendants", gen(
|
||||
{
|
||||
children = {
|
||||
{
|
||||
children = {},
|
||||
name = "Signal",
|
||||
token = "enum",
|
||||
},
|
||||
{
|
||||
parameters = {},
|
||||
return_types = {},
|
||||
name = "draw_to_cairo_context",
|
||||
token = "function",
|
||||
},
|
||||
{
|
||||
children = {
|
||||
{
|
||||
children = {},
|
||||
name = "Signal",
|
||||
token = "enum",
|
||||
},
|
||||
{
|
||||
parameters = {},
|
||||
return_types = {},
|
||||
name = "imagebox",
|
||||
metamethod = "__call",
|
||||
token = "metamethod",
|
||||
}
|
||||
},
|
||||
name = "Imagebox",
|
||||
module_path = "wibox.widget.imagebox",
|
||||
dependencies = {},
|
||||
global = false,
|
||||
token = "module",
|
||||
}
|
||||
},
|
||||
name = "Widget",
|
||||
module_path = "wibox.widget",
|
||||
dependencies = {},
|
||||
descendants = {
|
||||
Imagebox = "wibox.widget.imagebox",
|
||||
},
|
||||
global = false,
|
||||
token = "module",
|
||||
},
|
||||
[[
|
||||
-- This file was auto-generated.
|
||||
local type Imagebox = require("wibox.widget.imagebox")
|
||||
|
||||
local record Widget
|
||||
enum Signal
|
||||
end
|
||||
draw_to_cairo_context: function()
|
||||
imagebox: Imagebox
|
||||
end
|
||||
|
||||
return Widget
|
||||
]]))
|
||||
end)
|
||||
|
|
|
@ -27,6 +27,8 @@ describe("Scrap documentation", function()
|
|||
name = "Empty",
|
||||
module_path = "empty",
|
||||
dependencies = {},
|
||||
descendants = {},
|
||||
global = false,
|
||||
token = "module",
|
||||
}))
|
||||
|
||||
|
@ -89,6 +91,8 @@ describe("Scrap documentation", function()
|
|||
name = "Property_signal",
|
||||
module_path = "property_signal",
|
||||
dependencies = {},
|
||||
descendants = {},
|
||||
global = false,
|
||||
token = "module",
|
||||
}))
|
||||
|
||||
|
@ -202,6 +206,8 @@ describe("Scrap documentation", function()
|
|||
name = "Property_enum",
|
||||
module_path = "property_enum",
|
||||
dependencies = {},
|
||||
descendants = {},
|
||||
global = false,
|
||||
token = "module",
|
||||
}))
|
||||
|
||||
|
@ -244,6 +250,8 @@ describe("Scrap documentation", function()
|
|||
name = "Property_string",
|
||||
module_path = "property_string",
|
||||
dependencies = {},
|
||||
descendants = {},
|
||||
global = false,
|
||||
token = "module",
|
||||
}))
|
||||
|
||||
|
@ -311,6 +319,8 @@ describe("Scrap documentation", function()
|
|||
name = "Tag",
|
||||
module_path = "awful.tag",
|
||||
dependencies = {},
|
||||
descendants = {},
|
||||
global = false,
|
||||
token = "module",
|
||||
}))
|
||||
|
||||
|
@ -363,6 +373,8 @@ describe("Scrap documentation", function()
|
|||
name = "Signal",
|
||||
module_path = "signal",
|
||||
dependencies = {},
|
||||
descendants = {},
|
||||
global = false,
|
||||
token = "module",
|
||||
}))
|
||||
|
||||
|
@ -450,14 +462,16 @@ describe("Scrap documentation", function()
|
|||
token = "variable",
|
||||
},
|
||||
},
|
||||
return_types = { "boolean" },
|
||||
return_types = { { "boolean" }},
|
||||
name = "kill",
|
||||
token = "function",
|
||||
}
|
||||
},
|
||||
name = "Awesome",
|
||||
name = "awesome",
|
||||
module_path = "awesome",
|
||||
dependencies = {},
|
||||
descendants = {},
|
||||
global = false,
|
||||
token = "module",
|
||||
}))
|
||||
|
||||
|
@ -566,6 +580,7 @@ describe("Scrap documentation", function()
|
|||
}
|
||||
},
|
||||
name = "Focused_Args",
|
||||
global = false,
|
||||
token = "record",
|
||||
},
|
||||
{
|
||||
|
@ -576,7 +591,7 @@ describe("Scrap documentation", function()
|
|||
token = "variable",
|
||||
},
|
||||
},
|
||||
return_types = { "screen" },
|
||||
return_types = { { "screen" }},
|
||||
name = "focused",
|
||||
token = "function",
|
||||
},
|
||||
|
@ -584,6 +599,8 @@ describe("Scrap documentation", function()
|
|||
name = "Screen",
|
||||
module_path = "awful.screen",
|
||||
dependencies = {},
|
||||
descendants = {},
|
||||
global = false,
|
||||
token = "module",
|
||||
}))
|
||||
|
||||
|
@ -667,7 +684,7 @@ describe("Scrap documentation", function()
|
|||
token = "variable",
|
||||
}
|
||||
},
|
||||
return_types = { "table" },
|
||||
return_types = { { "table" }},
|
||||
name = "crush",
|
||||
token = "function",
|
||||
}
|
||||
|
@ -675,6 +692,8 @@ describe("Scrap documentation", function()
|
|||
name = "Table",
|
||||
module_path = "gears.table",
|
||||
dependencies = {},
|
||||
descendants = {},
|
||||
global = false,
|
||||
token = "module",
|
||||
}))
|
||||
|
||||
|
@ -759,7 +778,7 @@ describe("Scrap documentation", function()
|
|||
token = "variable",
|
||||
},
|
||||
},
|
||||
return_types = { "table" },
|
||||
return_types = { { "table" } },
|
||||
name = "tags",
|
||||
token = "function",
|
||||
},
|
||||
|
@ -767,6 +786,8 @@ describe("Scrap documentation", function()
|
|||
name = "Client",
|
||||
module_path = "awful.client",
|
||||
dependencies = {},
|
||||
descendants = {},
|
||||
global = false,
|
||||
token = "module",
|
||||
}))
|
||||
|
||||
|
@ -810,14 +831,145 @@ describe("Scrap documentation", function()
|
|||
name = "Client",
|
||||
module_path = "awful.client",
|
||||
dependencies = {},
|
||||
descendants = {},
|
||||
global = false,
|
||||
token = "module",
|
||||
},
|
||||
{
|
||||
{
|
||||
parameters = {},
|
||||
return_types = { "integer" },
|
||||
return_types = { { "integer" } },
|
||||
name = "client.instances",
|
||||
token = "function",
|
||||
}
|
||||
}))
|
||||
|
||||
it("should parse function return union types and multiple return values", test(
|
||||
[[
|
||||
<h2 class="section-header "><a name="Static_module_functions"></a>Static module functions</h2>
|
||||
<dl class="function">
|
||||
<dt>
|
||||
<a class="copy-link js-copy-link" name="load_image" href="#load_image">🔗</a>
|
||||
<strong><span class="function_modname">awesome.</span>load_image <span class="function_args"> <b>(</b>name<b>)</b></span></strong>
|
||||
<span class="proptype">
|
||||
<span class="summary_type"> -> (gears.surface, nil <i>or</i> string)</span></span>
|
||||
<span class="baseclass">
|
||||
</span>
|
||||
</dt>
|
||||
<dd>
|
||||
Load an image from a given path.
|
||||
<h3>Returns:</h3>
|
||||
<ol>
|
||||
<li>
|
||||
<span class="types"><span class="type">gears.surface</span></span>
|
||||
A cairo surface as light user datum.
|
||||
</li>
|
||||
<li>
|
||||
<span class="types"><span class="type">nil</span> or <a class="type" href="https://www.lua.org/manual/5.4/manual.html#6.4" target="_blank">string</a></span>
|
||||
The error message, if any.
|
||||
</li>
|
||||
</ol>
|
||||
</dd>
|
||||
</dl>
|
||||
]],
|
||||
"awesome",
|
||||
{
|
||||
children = {
|
||||
{
|
||||
children = {},
|
||||
name = "Signal",
|
||||
token = "enum",
|
||||
},
|
||||
{
|
||||
parameters = {},
|
||||
return_types = { { "gears.surface" }, { "nil", "string" } },
|
||||
name = "load_image",
|
||||
token = "function",
|
||||
}
|
||||
},
|
||||
name = "awesome",
|
||||
module_path = "awesome",
|
||||
dependencies = {},
|
||||
descendants = {},
|
||||
global = false,
|
||||
token = "module",
|
||||
}))
|
||||
|
||||
it("should produce a __call metamethod for constructor", test(
|
||||
[[
|
||||
<h2 class="section-header "><a name="Constructors"></a>Constructors</h2>
|
||||
<dl class="function">
|
||||
<dt>
|
||||
<a class="copy-link js-copy-link" name="gears.timer" href="#gears.timer">🔗</a>
|
||||
<strong>gears.timer <span class="function_named_args"><b>{</b>[args]<b>}</b></span></strong>
|
||||
<span class="baseclass"></span>
|
||||
</dt>
|
||||
<dd>
|
||||
</dd>
|
||||
</dl>
|
||||
]],
|
||||
"gears.timer",
|
||||
{
|
||||
children = {
|
||||
{
|
||||
children = {},
|
||||
name = "Signal",
|
||||
token = "enum",
|
||||
},
|
||||
{
|
||||
parameters = {
|
||||
{
|
||||
types = { "Timer" },
|
||||
name = "self",
|
||||
token = "variable",
|
||||
},
|
||||
},
|
||||
return_types = {},
|
||||
name = "timer",
|
||||
metamethod = "__call",
|
||||
token = "metamethod",
|
||||
}
|
||||
},
|
||||
name = "Timer",
|
||||
module_path = "gears.timer",
|
||||
dependencies = {},
|
||||
descendants = {},
|
||||
global = false,
|
||||
token = "module",
|
||||
}))
|
||||
|
||||
it("should produce Variable for content in the Fields section", test(
|
||||
[[
|
||||
<h2 class="section-header "><a name="Fields"></a>Fields</h2>
|
||||
<dl class="function">
|
||||
<dt>
|
||||
<a class="copy-link js-copy-link" name="primary" href="#primary">🔗</a>
|
||||
<strong><span class="function_modname">screen.</span>primary</strong>
|
||||
<span class="proptype"><span class="summary_type">screen</span></span>
|
||||
<span class="baseclass"></span>
|
||||
</dt>
|
||||
<dd></dd>
|
||||
</dl>
|
||||
]],
|
||||
"field_variable",
|
||||
{
|
||||
children = {
|
||||
{
|
||||
children = {},
|
||||
name = "Signal",
|
||||
token = "enum",
|
||||
},
|
||||
{
|
||||
name = "primary",
|
||||
types = { "screen" },
|
||||
token = "variable",
|
||||
}
|
||||
},
|
||||
name = "Field_variable",
|
||||
module_path = "field_variable",
|
||||
dependencies = {},
|
||||
descendants = {},
|
||||
global = false,
|
||||
token = "module",
|
||||
}))
|
||||
end)
|
||||
|
|
|
@ -1,18 +1,21 @@
|
|||
local type Node = require("awesomewmdtl.types.Node")
|
||||
|
||||
local basic_nodes <total>: { Node.Token : function(name: string, ...: any): Node } = {
|
||||
module = function(name: string, module_path: string): Node
|
||||
module = function(name: string, module_path: string, global: boolean): Node
|
||||
return {
|
||||
token = "module",
|
||||
global = global,
|
||||
name = name,
|
||||
module_path = module_path,
|
||||
dependencies = {},
|
||||
descendants = {},
|
||||
children = {},
|
||||
}
|
||||
end,
|
||||
record = function(name: string): Node
|
||||
record = function(name: string, global: boolean): Node
|
||||
return {
|
||||
token = "record",
|
||||
global = global,
|
||||
name = name,
|
||||
children = {},
|
||||
}
|
||||
|
@ -53,6 +56,14 @@ local basic_nodes <total>: { Node.Token : function(name: string, ...: any): Node
|
|||
return_types = {},
|
||||
}
|
||||
end,
|
||||
type = function(name: string, types: { string }, global: boolean): Node
|
||||
return {
|
||||
token = "type",
|
||||
global = global,
|
||||
name = name,
|
||||
types = types,
|
||||
}
|
||||
end
|
||||
}
|
||||
|
||||
local function create_node(token: Node.Token, name: string, ...: any): Node
|
||||
|
@ -60,6 +71,47 @@ local function create_node(token: Node.Token, name: string, ...: any): Node
|
|||
return node
|
||||
end
|
||||
|
||||
-- TODO : be less permissive and allow to merge only module ?
|
||||
local function merge_nodes(node: Node, other: Node): Node
|
||||
if node.token ~= other.token then
|
||||
error("Cannot merge nodes of different types")
|
||||
end
|
||||
if node.name ~= other.name then
|
||||
error("Cannot merge nodes of different names")
|
||||
end
|
||||
if node.module_path ~= other.module_path then
|
||||
error("Cannot merge nodes of different module paths")
|
||||
end
|
||||
|
||||
-- Basic fields should be overwritten by the new values
|
||||
-- Teal wants us to use enums value to index a record, but it fails to understand my enum with
|
||||
-- any other key from Node, so I'm forcing it to cooperate for now
|
||||
local enum NodeField
|
||||
"types"
|
||||
end
|
||||
for _, field in ipairs({"global", "types", "parameters", "return_types", "metamethod"}) do
|
||||
local f = field as NodeField
|
||||
node[f] = other[f]
|
||||
end
|
||||
|
||||
-- Children should be merged
|
||||
local children: { string : integer } = {}
|
||||
for i, child in ipairs(node.children) do
|
||||
children[child.name] = i
|
||||
end
|
||||
for _, child in ipairs(other.children) do
|
||||
if children[child.name] ~= nil then
|
||||
table.remove(node.children, children[child.name])
|
||||
end
|
||||
table.insert(node.children, child)
|
||||
end
|
||||
|
||||
-- Dependencies should be merged
|
||||
for name, path in pairs(other.dependencies) do
|
||||
node.dependencies[name] = path
|
||||
end
|
||||
end
|
||||
|
||||
local function iter_children(node: Node): function(): integer, Node
|
||||
if node.children == nil then
|
||||
return function(): integer, Node end
|
||||
|
@ -67,6 +119,7 @@ local function iter_children(node: Node): function(): integer, Node
|
|||
return ipairs(node.children)
|
||||
end
|
||||
|
||||
-- TODO : deprecate in favor of the iterator definition ?
|
||||
local function in_order_visitor(node: Node, visitor: function(Node))
|
||||
for _, child in iter_children(node) do
|
||||
in_order_visitor(child, visitor)
|
||||
|
@ -74,8 +127,28 @@ local function in_order_visitor(node: Node, visitor: function(Node))
|
|||
visitor(node)
|
||||
end
|
||||
|
||||
local function iter_in_order(node: Node): function(): Node
|
||||
local stack: { Node } = {}
|
||||
|
||||
local function traverse(n: Node)
|
||||
for _, child in iter_children(n) do
|
||||
traverse(child)
|
||||
end
|
||||
table.insert(stack, n)
|
||||
end
|
||||
traverse(node)
|
||||
|
||||
local i = 0
|
||||
return function(): Node
|
||||
i = i + 1
|
||||
return stack[i]
|
||||
end
|
||||
end
|
||||
|
||||
return {
|
||||
create_node = create_node,
|
||||
merge_nodes = merge_nodes,
|
||||
iter_children = iter_children,
|
||||
in_order_visitor = in_order_visitor,
|
||||
iter_in_order = iter_in_order,
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
local ast = require("awesomewmdtl.ast")
|
||||
local type Dag = require("awesomewmdtl.types.Dag")
|
||||
local type Node = require("awesomewmdtl.types.Node")
|
||||
local utils <const> = require("awesomewmdtl.utils")
|
||||
|
@ -10,16 +11,90 @@ local function new(): Dag
|
|||
return dag
|
||||
end
|
||||
|
||||
local function push_module(dag: Dag, module_path: string, root_node: Node)
|
||||
dag.modules[module_path] = root_node
|
||||
local function push_module(dag: Dag, module_path: string, node: Node)
|
||||
local parent: Node = { children = dag.modules }
|
||||
local current_path = ""
|
||||
for breadcrumb in module_path:gmatch("([^%.]+)") do
|
||||
current_path = current_path == "" and breadcrumb or current_path .. "." .. breadcrumb
|
||||
|
||||
if current_path == node.module_path then
|
||||
local found = utils.find(parent.children, function(n: Node): boolean
|
||||
return n.module_path == node.module_path
|
||||
end)
|
||||
if found then
|
||||
ast.merge_nodes(found, node)
|
||||
else
|
||||
table.insert(parent.children, node)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
local current: Node = nil
|
||||
for _, n in ipairs(parent.children) do
|
||||
if n.module_path == current_path then
|
||||
current = n
|
||||
break
|
||||
end
|
||||
end
|
||||
if current == nil then
|
||||
current = {
|
||||
children = {},
|
||||
name = utils.capitalize(breadcrumb),
|
||||
module_path = current_path,
|
||||
dependencies = {},
|
||||
descendants = {},
|
||||
token = "module",
|
||||
}
|
||||
push_module(dag, current_path, current)
|
||||
end
|
||||
|
||||
parent = current
|
||||
end
|
||||
end
|
||||
|
||||
local function push_global_nodes(dag: Dag, nodes: { Node })
|
||||
utils.spread(dag.global_nodes, nodes)
|
||||
end
|
||||
|
||||
local function iter_modules(dag: Dag): function(): string, Node
|
||||
return pairs(dag.modules)
|
||||
local function iter_modules(dag: Dag): (function(): Node)
|
||||
local stack: { Node } = {}
|
||||
for _, root in ipairs(dag.modules) do
|
||||
for node in ast.iter_in_order(root) do
|
||||
if node.token == "module" then
|
||||
table.insert(stack, node)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local i = 0
|
||||
return function(): Node
|
||||
i = i + 1
|
||||
return stack[i]
|
||||
end
|
||||
end
|
||||
|
||||
local function iter_global_nodes(dag: Dag): (function(): integer, Node)
|
||||
return pairs(dag.global_nodes)
|
||||
end
|
||||
|
||||
local function find_module(dag: Dag, module_path: string): Node
|
||||
local current_path = ""
|
||||
local current: Node = { children = dag.modules }
|
||||
for breadcrumb in module_path:gmatch("([^%.]+)") do
|
||||
current_path = current_path == "" and breadcrumb or current_path .. "." .. breadcrumb
|
||||
for _, child in ipairs(current.children) do
|
||||
if child.module_path == module_path then
|
||||
return child
|
||||
end
|
||||
if child.module_path == current_path then
|
||||
current = child
|
||||
goto continue
|
||||
end
|
||||
end
|
||||
break
|
||||
::continue::
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
return {
|
||||
|
@ -27,4 +102,6 @@ return {
|
|||
push_module = push_module,
|
||||
push_global_nodes = push_global_nodes,
|
||||
iter_modules = iter_modules,
|
||||
iter_global_nodes = iter_global_nodes,
|
||||
find_module = find_module,
|
||||
}
|
||||
|
|
|
@ -9,13 +9,14 @@ local filesystem <const> = require("awesomewmdtl.filesystem")
|
|||
local printer <const> = require("awesomewmdtl.printer")
|
||||
local List <const> = require("pl.List")
|
||||
local logger <const> = require("awesomewmdtl.logger")
|
||||
local Map <const> = require("pl.Map")
|
||||
local Module_Info <const> = require("awesomewmdtl.entity.Module_Info")
|
||||
local module_dependencies <const> = require("awesomewmdtl.visitors.module_dependencies")
|
||||
local module_descendants <const> = require("awesomewmdtl.visitors.module_descendants")
|
||||
local type Node = require("awesomewmdtl.types.Node")
|
||||
local node_fixer <const> = require("awesomewmdtl.visitors.node_fixer")
|
||||
local property <const> = require("awesomewmdtl.property")
|
||||
local remove_duplicate_fields <const> = require("awesomewmdtl.visitors.remove_duplicate_fields")
|
||||
local scraper <const> = require("awesomewmdtl.scraper")
|
||||
local stringx <const> = require("pl.stringx")
|
||||
local type_mapping <const> = require("awesomewmdtl.visitors.type_mapping")
|
||||
local utils <const> = require("awesomewmdtl.utils")
|
||||
|
||||
|
@ -45,53 +46,6 @@ local function module_lists(
|
|||
return all_module_infos, module_infos, global_module_infos
|
||||
end
|
||||
|
||||
-- The module's children list produced can contain duplicates.
|
||||
-- We ignore them for now because they are dismissed when building a Map for the printer.
|
||||
local function modules_tree(modules: List<Module_Info.Module_Info>): Map<string, List<string>>
|
||||
local tree: Map<string, List<string>> = Map()
|
||||
for module in modules:iter() do
|
||||
local parent = module.name:gmatch("(.*)%.(.*)$")()
|
||||
if parent then
|
||||
local ancestors = stringx.split(parent, ".")
|
||||
for i = 1, #ancestors - 1 do
|
||||
local ancestor = ancestors:slice(1, i):join(".")
|
||||
if not tree:get(ancestor) then
|
||||
tree:set(ancestor, List())
|
||||
end
|
||||
if not tree:get(ancestor):contains(parent) then
|
||||
tree:get(ancestor):append(parent)
|
||||
end
|
||||
end
|
||||
local parent_node = tree:get(parent)
|
||||
if not parent_node then
|
||||
tree:set(parent, List())
|
||||
parent_node = tree:get(parent)
|
||||
end
|
||||
parent_node:append(module.name)
|
||||
end
|
||||
end
|
||||
return tree
|
||||
end
|
||||
|
||||
--- TODO : rewrite this to use the DAG
|
||||
local function do_module_init_definition(
|
||||
module_infos: List<Module_Info.Module_Info>
|
||||
)
|
||||
local tree = modules_tree(module_infos)
|
||||
for module, children in tree:iter() do
|
||||
-- TODO : this map should be coupled with the all_module_infos list
|
||||
local requires: Map<string, string> = Map()
|
||||
for child in children:iter() do
|
||||
local name = child:gmatch(".*%.(.*)$")()
|
||||
requires:set(name, child)
|
||||
end
|
||||
filesystem.file_writer.write(
|
||||
printer.module_init_definition.generate_teal(requires),
|
||||
property.out_directory .. "/" .. stringx.split(module, "."):slice(1, -1):join("/") .. "/init.d.tl"
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
--- TODO : rewrite the module_info thingy
|
||||
local all_module_infos, module_infos, global_module_infos = module_lists(
|
||||
property.base_url .. property.index_uri,
|
||||
|
@ -128,36 +82,102 @@ for module in module_infos:iter() do
|
|||
dag.push_global_nodes(module_dag, other_nodes)
|
||||
end
|
||||
|
||||
-- Push global nodes to the global module
|
||||
for _, mod in ipairs(property.capi_modules) do
|
||||
local node: Node = nil
|
||||
local index: integer
|
||||
for i, n in ipairs(module_dag.modules) do
|
||||
if n.module_path == mod then
|
||||
node = n
|
||||
index = i
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if node then
|
||||
node.global = true
|
||||
dag.push_global_nodes(module_dag, { node })
|
||||
table.remove(module_dag.modules, index)
|
||||
end
|
||||
end
|
||||
|
||||
-- Run the visitors
|
||||
for _,root in dag.iter_modules(module_dag) do
|
||||
for _,root in dag.iter_global_nodes(module_dag) do
|
||||
ast.in_order_visitor(root, function(node: Node)
|
||||
node_fixer.visit(node, root)
|
||||
end)
|
||||
ast.in_order_visitor(root, function(node: Node)
|
||||
type_mapping.visit(node, true)
|
||||
end)
|
||||
end
|
||||
|
||||
for root in dag.iter_modules(module_dag) do
|
||||
ast.in_order_visitor(root, function(node: Node)
|
||||
remove_duplicate_fields.visit(node)
|
||||
end)
|
||||
ast.in_order_visitor(root, function(node: Node)
|
||||
node_fixer.visit(node, root)
|
||||
end)
|
||||
ast.in_order_visitor(root, function(node: Node)
|
||||
type_mapping.visit(node)
|
||||
end)
|
||||
ast.in_order_visitor(root, function(node: Node)
|
||||
module_dependencies.visit(node, root, module_dag)
|
||||
end)
|
||||
ast.in_order_visitor(root, function(node: Node)
|
||||
module_descendants.visit(node)
|
||||
end)
|
||||
end
|
||||
|
||||
-- Build the global module from dag.global_nodes
|
||||
--- TODO : todo
|
||||
-- Build the global_env_def.d.tl module from module_dag.global_nodes
|
||||
local global_nodes_by_record_kind <const>: { string : { Node } } = {}
|
||||
for _, node in dag.iter_global_nodes(module_dag) do
|
||||
local record_kind = node.name:gmatch("[^%.]*")() -- get the most left part of the lua name path representation
|
||||
if not global_nodes_by_record_kind[record_kind] then
|
||||
global_nodes_by_record_kind[record_kind] = {}
|
||||
end
|
||||
table.insert(global_nodes_by_record_kind[record_kind], node)
|
||||
end
|
||||
local global_module_ast <const> = ast.create_node("module", "global_env_def", "global_env_def", true)
|
||||
-- Declare global types
|
||||
table.insert(global_module_ast.children, ast.create_node("type", "Gears_Shape_Function", { "(function(cr: any, width: integer, height: integer))" }, true))
|
||||
table.insert(global_module_ast.children, ast.create_node("type", "Color", { "any" }, true))
|
||||
table.insert(global_module_ast.children, ast.create_node("type", "Cairo_Surface", { "any" }, true))
|
||||
table.insert(global_module_ast.children, ast.create_node("type", "Cairo_Context", { "any" }, true))
|
||||
table.insert(global_module_ast.children, ast.create_node("type", "Image", { "any" }, true))
|
||||
table.insert(global_module_ast.children, ast.create_node("type", "Awful_Placement_Function", { "function(d: any, args: table)" }, true))
|
||||
for record_kind, nodes in pairs(global_nodes_by_record_kind) do
|
||||
local record_kind_node = ast.create_node("record", record_kind, true)
|
||||
for _, node in ipairs(nodes) do
|
||||
node.name = node.name:gsub(record_kind .. "%.", "")
|
||||
table.insert(record_kind_node.children, node)
|
||||
end
|
||||
table.insert(global_module_ast.children, record_kind_node)
|
||||
end
|
||||
|
||||
--- TODO : this is fun, but we need to do something with it
|
||||
-- Write the DAG to a file
|
||||
-- local inspect = require("inspect")
|
||||
-- filesystem.file_writer.write(
|
||||
-- inspect(module_dag, { newline = "\n", indent = " ", depth = 2 }),
|
||||
-- inspect(module_dag, { newline = "\n", indent = " " }),
|
||||
-- "generated_dag.lua"
|
||||
-- )
|
||||
|
||||
log:info("Preprocessing finished")
|
||||
|
||||
-- Write modules types definitions to files
|
||||
for module_path, root in dag.iter_modules(module_dag) do
|
||||
for root in dag.iter_modules(module_dag) do
|
||||
filesystem.file_writer.write(
|
||||
printer.teal_type_definition.printer(root),
|
||||
property.out_directory .. "/" .. module_path:gsub("%.", "/") .. ".d.tl"
|
||||
property.out_directory .. "/" .. root.module_path:gsub("%.", "/") .. ".d.tl"
|
||||
)
|
||||
end
|
||||
|
||||
do_module_init_definition(module_infos)
|
||||
|
||||
-- Write global types definition to file
|
||||
filesystem.file_writer.write(
|
||||
printer.teal_type_definition.printer(global_module_ast),
|
||||
property.out_directory .. "/global_env_def.d.tl"
|
||||
)
|
||||
|
||||
log:info("Module init files generated")
|
||||
|
|
|
@ -6,11 +6,33 @@ local utils = require("awesomewmdtl.utils")
|
|||
|
||||
local log = logger.log("scraper")
|
||||
|
||||
local function render_types(types: { string }): string
|
||||
local GEN_TEXT <const> = "-- This file was auto-generated.\n"
|
||||
|
||||
local function render_types(types: { string }, separator: string, with_colon_prefix: boolean): string
|
||||
if not types or #types == 0 then
|
||||
return ""
|
||||
end
|
||||
return ": " .. table.concat(types, " | ")
|
||||
return string.format(
|
||||
"%s%s",
|
||||
with_colon_prefix and ": " or "",
|
||||
table.concat(types, separator))
|
||||
end
|
||||
|
||||
local function render_function_return_types(types: { { string } }): string
|
||||
if not types or #types == 0 then
|
||||
return ""
|
||||
end
|
||||
|
||||
local positional_return_types = utils.map(types, function (t: { string }): string
|
||||
return render_types(t, " | ")
|
||||
end)
|
||||
|
||||
return ": " .. table.concat(positional_return_types, ", ")
|
||||
end
|
||||
|
||||
local function render_metamethod_type(metamethod: Node.Metamethod): string
|
||||
-- Node.Metamethod enum matches the metamethods names, so we can simply print them as-is
|
||||
return metamethod
|
||||
end
|
||||
|
||||
local function dedent(str: string): string
|
||||
|
@ -37,30 +59,63 @@ local function render_require(dependencies: { string : string }): string
|
|||
return generated
|
||||
end
|
||||
|
||||
local function render_descendant(descendants: { string : string }): string
|
||||
local generated = ""
|
||||
for descendant in utils.pairsByKeys(descendants) do
|
||||
generated = generated .. string.format("%s: %s\n", utils.lowercase(descendant), descendant)
|
||||
end
|
||||
return generated
|
||||
end
|
||||
|
||||
local record Node_Printer_Function
|
||||
on_node: function(node: Node, indent_level: integer): string, integer
|
||||
before_node: nil | function(node: Node, indent_level: integer): string, integer
|
||||
after_node: nil | function(node: Node, indent_level: integer): string, integer
|
||||
on_node: function(node: Node, indent_level: integer, parent_token: Node.Token): string, integer
|
||||
-- optional functions
|
||||
before_node: function(node: Node, indent_level: integer, parent_token: Node.Token): string, integer
|
||||
after_node: function(node: Node, indent_level: integer, parent_token: Node.Token): string, integer
|
||||
end
|
||||
|
||||
-- pre-declare functions to prevent forward reference errors
|
||||
local print_teal: function(node: Node, indent_level: integer | nil): string
|
||||
local print_teal: function(node: Node, indent_level: integer, parent_node: Node): string
|
||||
local print_children: function(node: Node): string
|
||||
|
||||
local node_printer <total>: { Node.Token : Node_Printer_Function } = {
|
||||
["module"] = {
|
||||
before_node = function(node: Node, indent_level: integer): string, integer
|
||||
before_node = function(node: Node, indent_level: integer, parent_token: Node.Token): string, integer
|
||||
if "module" == parent_token then
|
||||
return "", indent_level
|
||||
end
|
||||
if node.global then
|
||||
return "", indent_level
|
||||
end
|
||||
return render_code(
|
||||
string.format(
|
||||
"-- This file was auto-generated.\n%s\nlocal record %s",
|
||||
render_require(node.dependencies), -- last require statement will have a newline
|
||||
"%s%s\nlocal record %s",
|
||||
GEN_TEXT,
|
||||
render_require(
|
||||
utils.merge_map(
|
||||
node.dependencies,
|
||||
node.descendants)), -- last require statement will have a newline
|
||||
node.name),
|
||||
indent_level), indent_level + 1
|
||||
end,
|
||||
on_node = function(node: Node, indent_level: integer): string, integer
|
||||
return render_code(print_children(node), indent_level), indent_level
|
||||
on_node = function(node: Node, indent_level: integer, parent_token: Node.Token): string, integer
|
||||
if "module" == parent_token then
|
||||
return "", indent_level
|
||||
end
|
||||
return render_code(
|
||||
string.format(
|
||||
"%s%s",
|
||||
render_descendant(node.descendants),
|
||||
print_children(node)
|
||||
), indent_level), indent_level
|
||||
end,
|
||||
after_node = function(node: Node, indent_level: integer): string, integer
|
||||
after_node = function(node: Node, indent_level: integer, parent_token: Node.Token): string, integer
|
||||
if "module" == parent_token then
|
||||
return "", indent_level
|
||||
end
|
||||
if node.global then
|
||||
return "", indent_level
|
||||
end
|
||||
return render_code("end", indent_level - 1) ..
|
||||
"\n" ..
|
||||
render_code(
|
||||
|
@ -73,7 +128,8 @@ local node_printer <total>: { Node.Token : Node_Printer_Function } = {
|
|||
before_node = function(node: Node, indent_level: integer): string, integer
|
||||
return render_code(
|
||||
string.format(
|
||||
"record %s",
|
||||
"%srecord %s",
|
||||
node.global and "\nglobal " or "",
|
||||
node.name),
|
||||
indent_level), indent_level + 1
|
||||
end,
|
||||
|
@ -110,7 +166,7 @@ local node_printer <total>: { Node.Token : Node_Printer_Function } = {
|
|||
string.format(
|
||||
"%s%s",
|
||||
node.name,
|
||||
render_types(node.types)),
|
||||
render_types(node.types, " | ", true)),
|
||||
indent_level), indent_level
|
||||
end,
|
||||
},
|
||||
|
@ -125,30 +181,56 @@ local node_printer <total>: { Node.Token : Node_Printer_Function } = {
|
|||
"%s: function(%s)%s",
|
||||
node.name,
|
||||
table.concat(args, ", "),
|
||||
render_types(node.return_types)),
|
||||
render_function_return_types(node.return_types)
|
||||
),
|
||||
indent_level), indent_level
|
||||
end,
|
||||
},
|
||||
["metamethod"] = {
|
||||
on_node = function(): string, integer
|
||||
log:warn("Metamethods are not supported yet")
|
||||
on_node = function(node: Node, indent_level: integer): string, integer
|
||||
local args = {}
|
||||
for _, parameter in ipairs(node.parameters) do
|
||||
table.insert(args, print_teal(parameter):sub(1, -2)) -- need to remove the newline ending
|
||||
end
|
||||
return render_code(
|
||||
string.format(
|
||||
"metamethod %s: function(%s)%s",
|
||||
render_metamethod_type(node.metamethod),
|
||||
table.concat(args, ", "),
|
||||
render_function_return_types(node.return_types)
|
||||
),
|
||||
indent_level), indent_level
|
||||
end,
|
||||
}
|
||||
},
|
||||
["type"] = {
|
||||
on_node = function(node: Node, indent_level: integer): string, integer
|
||||
return render_code(
|
||||
string.format(
|
||||
"%stype %s = %s",
|
||||
node.global and "\nglobal " or "",
|
||||
node.name,
|
||||
render_types(node.types, " | ")),
|
||||
indent_level), indent_level
|
||||
end,
|
||||
},
|
||||
}
|
||||
|
||||
function print_teal(node: Node, indent_level: integer | nil): string
|
||||
function print_teal(node: Node,
|
||||
-- optional parameters
|
||||
indent_level: integer, parent_node: Node): string
|
||||
indent_level = indent_level or 0
|
||||
local parent_node_token = parent_node and parent_node.token
|
||||
local printer = node_printer[node.token]
|
||||
local generated = ""
|
||||
local full_generated = ""
|
||||
if printer.before_node then
|
||||
generated, indent_level = (printer.before_node as function(Node, integer): string, integer)(node, indent_level)
|
||||
generated, indent_level = printer.before_node(node, indent_level, parent_node_token)
|
||||
full_generated = generated
|
||||
end
|
||||
generated, indent_level = printer.on_node(node, indent_level)
|
||||
generated, indent_level = printer.on_node(node, indent_level, parent_node_token)
|
||||
full_generated = full_generated .. generated
|
||||
if printer.after_node then
|
||||
generated, indent_level = (printer.after_node as function(Node, integer): string, integer)(node, indent_level)
|
||||
generated, indent_level = printer.after_node(node, indent_level, parent_node_token)
|
||||
full_generated = full_generated .. generated
|
||||
end
|
||||
return full_generated
|
||||
|
@ -157,7 +239,7 @@ end
|
|||
function print_children(node: Node): string
|
||||
local generated = ""
|
||||
for _, child in ast.iter_children(node) do
|
||||
generated = generated .. print_teal(child)
|
||||
generated = generated .. print_teal(child, 0, node)
|
||||
end
|
||||
return generated
|
||||
end
|
||||
|
|
|
@ -18,16 +18,13 @@ local record Property
|
|||
end
|
||||
|
||||
local property: Property = {
|
||||
-- base_url = "https://awesomewm.org/apidoc",
|
||||
base_url = "https://awesomewm.org/apidoc",
|
||||
-- base_url = "file:///usr/share/doc/awesome/doc",
|
||||
base_url = "file:///home/aireone/documents/prog/awesome/build/doc",
|
||||
index_uri = "/index.html",
|
||||
out_directory = "generated",
|
||||
capi_modules = {
|
||||
"awesome",
|
||||
"client and awful.client",
|
||||
"screen and awful.screen",
|
||||
"tag and awful.tag",
|
||||
"drawable",
|
||||
},
|
||||
ignored_modules = {
|
||||
-- Sample files
|
||||
|
@ -35,33 +32,33 @@ local property: Property = {
|
|||
"theme.lua",
|
||||
|
||||
-- Utility libraries
|
||||
"gears.debug",
|
||||
"gears.filesystem",
|
||||
"gears.geometry",
|
||||
"gears.math",
|
||||
"gears.object",
|
||||
"gears.protected_call",
|
||||
"gears.sort",
|
||||
"gears.string",
|
||||
"gears.table",
|
||||
"gears.wallpaper",
|
||||
-- "gears.debug",
|
||||
-- "gears.filesystem",
|
||||
-- "gears.geometry",
|
||||
-- "gears.math",
|
||||
-- "gears.object",
|
||||
-- "gears.protected_call",
|
||||
-- "gears.sort",
|
||||
-- "gears.string",
|
||||
-- "gears.table",
|
||||
-- "gears.wallpaper",
|
||||
|
||||
-- Theme related libraries
|
||||
"beautiful",
|
||||
-- "beautiful",
|
||||
"gears.color",
|
||||
"gears.shape",
|
||||
-- "gears.shape",
|
||||
|
||||
-- Classes
|
||||
"awful.widget.common",
|
||||
"gears.cache",
|
||||
"gears.matrix",
|
||||
"menubar.icon_theme",
|
||||
"menubar.index_theme",
|
||||
"signals",
|
||||
"wibox.drawable",
|
||||
"wibox.hierarchy",
|
||||
"wibox.widget.base",
|
||||
"xproperties",
|
||||
-- "awful.widget.common",
|
||||
-- "gears.cache",
|
||||
-- "gears.matrix",
|
||||
-- "menubar.icon_theme",
|
||||
-- "menubar.index_theme",
|
||||
-- "signals",
|
||||
-- "wibox.drawable",
|
||||
-- "wibox.hierarchy",
|
||||
-- "wibox.widget.base",
|
||||
-- "xproperties",
|
||||
|
||||
-- Documentation
|
||||
"Authors",
|
||||
|
|
|
@ -18,7 +18,11 @@ local function parse_parameter_types(parameter_type: string): { string }
|
|||
end
|
||||
|
||||
local types = {}
|
||||
for t in stringx.split(parameter_type, " or "):iter() do
|
||||
for t in stringx.split(parameter_type)
|
||||
:filter(
|
||||
function(s: string): boolean
|
||||
return s ~= "or" and s ~= ","
|
||||
end):iter() do
|
||||
table.insert(types, t)
|
||||
end
|
||||
return types
|
||||
|
@ -30,7 +34,7 @@ local function extract_item_name(item_name_node: scan.HTMLNode): string, string
|
|||
end
|
||||
local module_name_node <const> = scraper_utils.find(item_name_node:outer_html(), "span.function_modname")[1]
|
||||
local module_name = module_name_node and module_name_node:inner_text():gsub("[%.:]$", "")
|
||||
local name <const> = item_name_node:inner_text():gsub("^.*[%.:](.+)%s*[%(%{].*[%)%}]", "%1")
|
||||
local name <const> = item_name_node:inner_text():gsub("(.+)[%(%{].*$", "%1"):gsub("^.*[%.:](.+)", "%1")
|
||||
return utils.sanitize_string(name), module_name and utils.sanitize_string(module_name) or nil
|
||||
end
|
||||
|
||||
|
@ -50,6 +54,12 @@ local function extract_function_parameters(table_html: string, function_name: st
|
|||
local name <const> = extract_node_text(name_node)
|
||||
local types <const> = parse_parameter_types(extract_node_text(types_node))
|
||||
|
||||
-- If the name contains a dot, then it's a nested field in a table
|
||||
-- We don't support this yet, so we just ignore it
|
||||
if name:match("%.") then
|
||||
return nil
|
||||
end
|
||||
|
||||
-- Add a field to the current parameter type record
|
||||
if tr.attr ~= nil and tr.attr.class == "see_also_sublist" and is_populating_parameters_types then
|
||||
local field = ast.create_node("variable", name)
|
||||
|
@ -77,7 +87,7 @@ local function extract_function_parameters(table_html: string, function_name: st
|
|||
"%s_%s",
|
||||
utils.capitalize(function_name),
|
||||
utils.capitalize(name))
|
||||
table.insert(parameters_types, ast.create_node("record", record_name))
|
||||
table.insert(parameters_types, ast.create_node("record", record_name, false))
|
||||
is_populating_parameters_types = true
|
||||
field.types = { record_name }
|
||||
end
|
||||
|
@ -93,8 +103,21 @@ local function extract_function_parameters(table_html: string, function_name: st
|
|||
return parameters, parameters_types
|
||||
end
|
||||
|
||||
local function extract_function_return_types(ol_html: string): { string }
|
||||
return scraper_utils.scrape(ol_html, "span.types .type", extract_node_text)
|
||||
local function extract_function_return_types(ol_html: string): { { string } }
|
||||
local positional_return_types = scraper_utils.find(
|
||||
ol_html,
|
||||
"span.types")
|
||||
|
||||
local types: { { string } } = {}
|
||||
for _,prt in ipairs(positional_return_types) do
|
||||
local ts: { string } = {}
|
||||
local union_types = scraper_utils.scrape(prt:outer_html(), ".type", extract_node_text)
|
||||
for _,t in ipairs(union_types) do
|
||||
table.insert(ts, t)
|
||||
end
|
||||
table.insert(types, ts)
|
||||
end
|
||||
return types
|
||||
end
|
||||
|
||||
local function extract_property_constraints(property_constraint_node: scan.HTMLNode): { string }
|
||||
|
@ -151,11 +174,11 @@ local function extract_section_functions(dl: string, module_name: string | nil):
|
|||
return functions, other_functions
|
||||
end
|
||||
|
||||
local function extract_section_variables(dl: string): { Node }, { string }
|
||||
local function extract_section_variables(dl: string, with_constraint: boolean): { Node }, { string }
|
||||
local query_selectors <const>: { string : string } = {
|
||||
variable_name = "dt strong",
|
||||
variable_summary_type = "dt span.summary_type",
|
||||
variable_property_constraint = "dd span.property_type",
|
||||
variable_property_constraint = with_constraint and "dd span.property_type",
|
||||
}
|
||||
|
||||
local variables <const>: { Node } = {}
|
||||
|
@ -171,11 +194,13 @@ local function extract_section_variables(dl: string): { Node }, { string }
|
|||
if #node.types == 1 and node.types[1] == "string" then
|
||||
log:debug("extract variable string with constraints, this is an enum", { name = node.name })
|
||||
local type_enum <const> = ast.create_node("enum", utils.capitalize(node.name))
|
||||
for _, constraint in ipairs(extract_property_constraints(nodes[query_selectors.variable_property_constraint])) do
|
||||
table.insert(
|
||||
type_enum.children,
|
||||
ast.create_node("identifier", (constraint:gsub(""", "")))
|
||||
)
|
||||
if with_constraint then
|
||||
for _, constraint in ipairs(extract_property_constraints(nodes[query_selectors.variable_property_constraint])) do
|
||||
table.insert(
|
||||
type_enum.children,
|
||||
ast.create_node("identifier", (constraint:gsub(""", "")))
|
||||
)
|
||||
end
|
||||
end
|
||||
if #type_enum.children == 0 then
|
||||
log:debug("Enum has no children, get back to variable", { name = node.name })
|
||||
|
@ -198,9 +223,21 @@ local function extract_section_signal(dl: string): { string }
|
|||
return scraper_utils.scrape(dl, selector, extract_node_text)
|
||||
end
|
||||
|
||||
local function add_self_parameter(function_node: Node, record_name: string)
|
||||
local self_parameter = ast.create_node("variable", "self")
|
||||
self_parameter.types = { record_name }
|
||||
table.insert(function_node.parameters, 1, self_parameter)
|
||||
end
|
||||
|
||||
local function transform_to_call_metamethod(function_node: Node)
|
||||
function_node.token = "metamethod"
|
||||
function_node.metamethod = "__call"
|
||||
end
|
||||
|
||||
local enum Section
|
||||
"Constructors"
|
||||
"Static module functions"
|
||||
"Fields"
|
||||
"Object properties"
|
||||
"Object methods"
|
||||
"Signals"
|
||||
|
@ -211,11 +248,12 @@ end
|
|||
-- - Nodes that should be added to the global scope
|
||||
-- - Strings that should be added to the record Signals
|
||||
local section_scrapers <total>: { Section : function(html: string, record_name: string, module_name: string): { Node }, { Node }, { string } } = {
|
||||
["Constructors"] = function(html: string): { Node }, { Node }, { string }
|
||||
["Constructors"] = function(html: string, record_name: string): { Node }, { Node }, { string }
|
||||
local constructors <const> = extract_section_functions(html)
|
||||
for _, constructor in ipairs(constructors) do
|
||||
if constructor.token == "function" then
|
||||
constructor.name = "new"
|
||||
if constructor.token == "function" and constructor.name == utils.lowercase(record_name) then
|
||||
add_self_parameter(constructor, record_name)
|
||||
transform_to_call_metamethod(constructor)
|
||||
end
|
||||
end
|
||||
return constructors, {}, {}
|
||||
|
@ -224,17 +262,19 @@ local section_scrapers <total>: { Section : function(html: string, record_name:
|
|||
local static_functions, other_functions = extract_section_functions(html, module_name)
|
||||
return static_functions, other_functions, {}
|
||||
end,
|
||||
["Fields"] = function(html: string): { Node }, { Node }, { string }
|
||||
local fields = extract_section_variables(html)
|
||||
return fields, {}, {}
|
||||
end,
|
||||
["Object properties"] = function(html: string): { Node }, { Node }, { string }
|
||||
local properties, signals = extract_section_variables(html)
|
||||
local properties, signals = extract_section_variables(html, true)
|
||||
return properties, {}, signals
|
||||
end,
|
||||
["Object methods"] = function(html: string, record_name: string): { Node }, { Node }, { string }
|
||||
local methods <const> = extract_section_functions(html)
|
||||
for _, method in ipairs(methods) do
|
||||
if method.token == "function" then
|
||||
local self_parameter = ast.create_node("variable", "self")
|
||||
self_parameter.types = { record_name }
|
||||
table.insert(method.parameters, 1, self_parameter)
|
||||
add_self_parameter(method, record_name)
|
||||
end
|
||||
end
|
||||
return methods, {}, {}
|
||||
|
@ -257,12 +297,14 @@ function module.get_doc_from_page(html: string, module_path: string): Node, { No
|
|||
"dl.function",
|
||||
})
|
||||
|
||||
if #html_nodes:get "h2.section-header" ~= #html_nodes:get "dl.function" then
|
||||
if #html_nodes:get("h2.section-header") ~= #html_nodes:get("dl.function") then
|
||||
error "The list aren't the same size!"
|
||||
end
|
||||
|
||||
local record_name <const> = utils.capitalize((module_path:gsub(".*%.", "")))
|
||||
local module_root <const> = ast.create_node("module", record_name, module_path)
|
||||
-- Awesome is a special case, we don't want to capitalize it.
|
||||
-- I'm too lazy to make a special case for it because this project is in development for far too long and it's getting depressing
|
||||
local record_name <const> = module_path == "awesome" and "awesome" or utils.capitalize((module_path:gsub(".*%.", "")))
|
||||
local module_root <const> = ast.create_node("module", record_name, module_path, false)
|
||||
local other_nodes <const>: { Node } = {}
|
||||
|
||||
local module_signals_node <const> = ast.create_node("enum", "Signal")
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
local type Node = require("awesomewmdtl.types.Node")
|
||||
|
||||
local record Dag
|
||||
modules: { string : Node } -- module_path (AKA "full name" `package.module.name`) -> root_node (token = "module")
|
||||
modules: { Node } -- list of root modules
|
||||
global_nodes: { Node }
|
||||
end
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ local record Node
|
|||
"variable"
|
||||
"function"
|
||||
"metamethod"
|
||||
"type"
|
||||
end
|
||||
token: Token
|
||||
name: string
|
||||
|
@ -14,16 +15,26 @@ local record Node
|
|||
-- for "module", "record", "enum"
|
||||
children: { Node }
|
||||
|
||||
-- for "variable"
|
||||
-- for "variable" and "type"
|
||||
types: { string }
|
||||
|
||||
-- for "function" and "metamethod"
|
||||
parameters: { Node }
|
||||
return_types: { string }
|
||||
return_types: { { string } }
|
||||
|
||||
-- for "methamethod"
|
||||
enum Metamethod
|
||||
"__call"
|
||||
end
|
||||
metamethod: Metamethod
|
||||
|
||||
-- for "module"
|
||||
module_path: string
|
||||
dependencies: { string : string } -- module_name -> module_path
|
||||
descendants: { string : string } -- modules in children that should be written in the final type definition. module_name -> module_path
|
||||
|
||||
-- for "module", "record", "type"
|
||||
global: boolean
|
||||
end
|
||||
|
||||
return Node
|
||||
|
|
|
@ -13,6 +13,16 @@ function utils.has_item(t: table, item: any): any
|
|||
return nil
|
||||
end
|
||||
|
||||
function utils.find<T>(list: { T }, predicate: function(value: T, position: integer): boolean): T, integer
|
||||
for position, value in ipairs(list) do
|
||||
if predicate(value, position) then
|
||||
return value, position
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
function utils.filter<T>(list: { T }, predicate: function(value: T, position: integer): boolean): { T }
|
||||
local filtered: { T } = {}
|
||||
|
||||
|
@ -101,4 +111,27 @@ function utils.pairsByKeys<Key, Value>(list: { Key : Value }, comp: function(Key
|
|||
end
|
||||
end
|
||||
|
||||
-- We expect the user to type at the call site
|
||||
function utils.pipe(...: function): function(...: any): any...
|
||||
local funcs = { ... }
|
||||
return function(...: any): any...
|
||||
local res = ...
|
||||
for _, f in ipairs(funcs) do
|
||||
res = f(res)
|
||||
end
|
||||
return res
|
||||
end
|
||||
end
|
||||
|
||||
function utils.merge_map<T, U>(t1: { T : U }, t2: { T : U }): { T : U }
|
||||
local merged: { T : U } = {}
|
||||
for k, v in pairs(t1) do
|
||||
merged[k] = v
|
||||
end
|
||||
for k, v in pairs(t2) do
|
||||
merged[k] = v
|
||||
end
|
||||
return merged
|
||||
end
|
||||
|
||||
return utils
|
||||
|
|
|
@ -1,9 +1,31 @@
|
|||
local type Dag = require("awesomewmdtl.types.Dag")
|
||||
local dag = require("awesomewmdtl.dag")
|
||||
local type Node = require("awesomewmdtl.types.Node")
|
||||
local utils <const> = require("awesomewmdtl.utils")
|
||||
|
||||
local spread = utils.spread
|
||||
|
||||
-- Very hacky way to get the module path of a capi class
|
||||
-- We shouldn't rely on partial record for Node
|
||||
local capi_class <const>: { string : Node } = {
|
||||
Client = {
|
||||
name = "Client",
|
||||
module_path = "awful.client",
|
||||
},
|
||||
Layout = {
|
||||
name = "Layout",
|
||||
module_path = "awful.layout",
|
||||
},
|
||||
Screen = {
|
||||
name = "Screen",
|
||||
module_path = "awful.screen",
|
||||
},
|
||||
Tag = {
|
||||
name = "Tag",
|
||||
module_path = "awful.tag",
|
||||
},
|
||||
}
|
||||
|
||||
local function get_all_types_in_node(node: Node): { string }
|
||||
local parameters_types = {}
|
||||
if node.parameters then
|
||||
|
@ -11,11 +33,17 @@ local function get_all_types_in_node(node: Node): { string }
|
|||
spread(parameters_types, v.types)
|
||||
end
|
||||
end
|
||||
local return_types = {}
|
||||
if node.return_types then
|
||||
for _, rts in ipairs(node.return_types) do
|
||||
spread(return_types, rts)
|
||||
end
|
||||
end
|
||||
return spread(
|
||||
{},
|
||||
node.types or {},
|
||||
node.return_types or {},
|
||||
parameters_types or {})
|
||||
return_types,
|
||||
parameters_types)
|
||||
end
|
||||
|
||||
local function replace_in_node_type(node: Node, old_type: string, new_type: string)
|
||||
|
@ -38,9 +66,11 @@ local function replace_in_node_type(node: Node, old_type: string, new_type: stri
|
|||
end
|
||||
|
||||
if node.return_types then
|
||||
for i, t in ipairs(node.return_types) do
|
||||
if t == old_type then
|
||||
node.return_types[i] = new_type
|
||||
for i, rt in ipairs(node.return_types) do
|
||||
for j, t in ipairs(rt) do
|
||||
if t == old_type then
|
||||
node.return_types[i][j] = new_type
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -56,10 +86,24 @@ function Module_Dependencies.visit(node: Node, mod: Node, d: Dag)
|
|||
if type_name == mod.name then
|
||||
goto continue
|
||||
end
|
||||
if utils.has_item({
|
||||
"any",
|
||||
"number",
|
||||
"integer",
|
||||
"string",
|
||||
"boolean",
|
||||
"function",
|
||||
"nil",
|
||||
"table",
|
||||
}, type_name) then
|
||||
goto continue
|
||||
end
|
||||
|
||||
local dependency = d.modules[type_name] or d.modules[utils.lowercase(type_name)]
|
||||
local dependency = dag.find_module(d, type_name) or capi_class[type_name]
|
||||
if dependency then
|
||||
mod.dependencies[dependency.name] = dependency.module_path
|
||||
if dependency.name ~= mod.name then
|
||||
mod.dependencies[dependency.name] = dependency.module_path
|
||||
end
|
||||
replace_in_node_type(node, dependency.module_path, dependency.name)
|
||||
end
|
||||
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
local type Node = require("awesomewmdtl.types.Node")
|
||||
local utils = require("awesomewmdtl.utils")
|
||||
|
||||
local capitalize = utils.capitalize
|
||||
|
||||
local function get_descendants_module(node: Node): { string : string }
|
||||
local descendants_by_name: { string : string } = {}
|
||||
|
||||
for _, descendant in ipairs(node.children) do
|
||||
if descendant.token == "module" then
|
||||
descendants_by_name[descendant.name] = descendant.module_path
|
||||
end
|
||||
end
|
||||
|
||||
return descendants_by_name
|
||||
end
|
||||
|
||||
local record Module_Descendants
|
||||
visit: function(node: Node)
|
||||
end
|
||||
|
||||
function Module_Descendants.visit(node: Node)
|
||||
if node.token ~= "module" then
|
||||
return
|
||||
end
|
||||
|
||||
local descendants_by_name = get_descendants_module(node)
|
||||
|
||||
for _, descendant in ipairs(node.children) do
|
||||
if descendant.token ~= "module" and descendants_by_name[capitalize(descendant.name)] then
|
||||
descendants_by_name[capitalize(descendant.name)] = nil
|
||||
end
|
||||
end
|
||||
|
||||
node.descendants = descendants_by_name
|
||||
end
|
||||
|
||||
return Module_Descendants
|
|
@ -0,0 +1,148 @@
|
|||
local type Node = require("awesomewmdtl.types.Node")
|
||||
|
||||
-- Teal can't define nested Map types yet, so we have to define a type for the nested map.
|
||||
local type New_Node_By_Name = { string : Node }
|
||||
|
||||
-- This is a map of module paths to a map of node names to a map of node keys to new values.
|
||||
-- This is used to fix nodes where either
|
||||
-- - Teal doesn't have a proper way to handle the types
|
||||
-- - The Awesome API is too confusing to be translated to Teal
|
||||
|
||||
-- EVERYTHING IN HERE IS TEMPORARY AND SHOULD BE REMOVED!
|
||||
-- EVERYTHING IN HERE IS TEMPORARY AND SHOULD BE REMOVED!
|
||||
-- EVERYTHING IN HERE IS TEMPORARY AND SHOULD BE REMOVED!
|
||||
|
||||
local node_fixer <const>: { string : New_Node_By_Name } = {
|
||||
["awful.titlebar"] = {
|
||||
new = {
|
||||
return_types = { { "Titlebar" } }, -- The Awesome APIDoc have to updated
|
||||
},
|
||||
},
|
||||
["awful.widget.prompt"] = {
|
||||
set_shape = {
|
||||
parameters = {
|
||||
{ token = "variable", name = "self", types = { "Prompt" } },
|
||||
{ token = "variable", name = "shape", types = { "Gears_Shape_Function" } }, -- cannot discriminate a union between multiple function types: Gears_Shape_Function | function(...: <any type>): <any type>...
|
||||
},
|
||||
},
|
||||
},
|
||||
["gears.filesystem"] = {
|
||||
get_themes_dir = {
|
||||
return_types = { { "string" } }, -- The Awesome APIDoc have to updated
|
||||
},
|
||||
},
|
||||
["gears.string"] = {
|
||||
split = { -- psplit is documented as split in the APIDoc
|
||||
parameters = {
|
||||
{ token = "variable", name = "s", types = { "string" } },
|
||||
{ token = "variable", name = "sep", types = { "string" } }, -- psplit optional parameter breaks the parser
|
||||
},
|
||||
},
|
||||
},
|
||||
["gears.surface"] = {
|
||||
apply_shape_bounding = {
|
||||
parameters = {
|
||||
{ token = "variable", name = "draw", types = { "any" } },
|
||||
{ token = "variable", name = "shape", types = { "Gears_Shape_Function" } },
|
||||
{ token = "variable", name = "...", types = { "any" } },
|
||||
},
|
||||
},
|
||||
},
|
||||
["naughty.widget.background"] = {
|
||||
set_shape = {
|
||||
parameters = {
|
||||
{ token = "variable", name = "self", types = { "Background" } },
|
||||
{ token = "variable", name = "shape", types = { "Gears_Shape_Function" } }, -- cannot discriminate a union between multiple function types: Gears_Shape_Function | function
|
||||
},
|
||||
},
|
||||
},
|
||||
["wibox.container.background"] = {
|
||||
background = {
|
||||
parameters = {
|
||||
{ token = "variable", name = "self", types = { "Background" } },
|
||||
{ token = "variable", name = "widget", types = { "Widget" } },
|
||||
{ token = "variable", name = "bg", types = { "Color" } },
|
||||
{ token = "variable", name = "shape", types = { "Gears_Shape_Function" } }, -- cannot discriminate a union between multiple function types: Gears_Shape_Function | function
|
||||
},
|
||||
},
|
||||
set_shape = {
|
||||
parameters = {
|
||||
{ token = "variable", name = "self", types = { "Background" } },
|
||||
{ token = "variable", name = "shape", types = { "Gears_Shape_Function" } }, -- cannot discriminate a union between multiple function types: Gears_Shape_Function | function(...: <any type>): <any type>
|
||||
},
|
||||
},
|
||||
},
|
||||
["wibox.container.tile"] = {
|
||||
Tile_Args = {
|
||||
children = { -- widget is documented twice in the APIDoc
|
||||
{
|
||||
name = "widget",
|
||||
token = "variable",
|
||||
types = { "Widget" }
|
||||
}, {
|
||||
name = "halign",
|
||||
token = "variable",
|
||||
types = { "string" }
|
||||
}, {
|
||||
name = "valign",
|
||||
token = "variable",
|
||||
types = { "string" }
|
||||
}, {
|
||||
name = "horizontal_spacing",
|
||||
token = "variable",
|
||||
types = { "number" }
|
||||
}, {
|
||||
name = "vertical_spacing",
|
||||
token = "variable",
|
||||
types = { "number" }
|
||||
}, {
|
||||
name = "horizontal_crop",
|
||||
token = "variable",
|
||||
types = { "boolean" }
|
||||
}, {
|
||||
name = "vertical_crop",
|
||||
token = "variable",
|
||||
types = { "boolean" }
|
||||
}, {
|
||||
name = "tiled",
|
||||
token = "variable",
|
||||
types = { "boolean" }
|
||||
}, {
|
||||
name = "fill_vertical",
|
||||
token = "variable",
|
||||
types = { "boolean" }
|
||||
}, {
|
||||
name = "fill_horizontal",
|
||||
token = "variable",
|
||||
types = { "boolean" }
|
||||
}, {
|
||||
name = "content_fill_vertical",
|
||||
token = "variable",
|
||||
types = { "boolean" }
|
||||
}, {
|
||||
name = "content_fill_horizontal",
|
||||
token = "variable",
|
||||
types = { "boolean" }
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
local record Node_Fixer
|
||||
visit: function(node: Node, mod: Node)
|
||||
end
|
||||
|
||||
function Node_Fixer.visit(node: Node, mod: Node)
|
||||
if not (node_fixer[mod.module_path] and node_fixer[mod.module_path][node.name]) then
|
||||
return
|
||||
end
|
||||
|
||||
for k, v in pairs(node_fixer[mod.module_path][node.name] as { string : any }) do
|
||||
-- Teal can't index `node` with our k,v
|
||||
local n <const> = node as { string : any }
|
||||
n[k] = v
|
||||
end
|
||||
end
|
||||
|
||||
return Node_Fixer
|
|
@ -0,0 +1,31 @@
|
|||
local type Node = require("awesomewmdtl.types.Node")
|
||||
local utils <const> = require("awesomewmdtl.utils")
|
||||
|
||||
local has_item <const> = utils.has_item
|
||||
|
||||
-- This is quick hack to remove duplicate fields from a module
|
||||
-- We can have duplicated fields in a module, because we currently
|
||||
-- don't make difference between module record and instance record.
|
||||
-- So static module fields and instance level fields are mixed together.
|
||||
|
||||
local record Remove_Duplicate_Fields
|
||||
visit: function(node: Node)
|
||||
end
|
||||
|
||||
function Remove_Duplicate_Fields.visit(node: Node)
|
||||
if node.token ~= "module" then
|
||||
return
|
||||
end
|
||||
|
||||
local fields: { string } = {}
|
||||
|
||||
for i, n in ipairs(node.children) do
|
||||
if has_item(fields, n.name) then
|
||||
table.remove(node.children, i)
|
||||
else
|
||||
table.insert(fields, n.name)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return Remove_Duplicate_Fields
|
|
@ -1,31 +1,60 @@
|
|||
local type Node = require("awesomewmdtl.types.Node")
|
||||
|
||||
-- Special types I don't want to deal with for now
|
||||
local gears_shape_function = "function(cr: any, width: integer, height: integer)"
|
||||
|
||||
local type_map <const>: { string : string } = {
|
||||
awesome = "Awesome",
|
||||
Awesome = "awesome",
|
||||
bool = "boolean",
|
||||
["surface._native"] = "Cairo_Surface",
|
||||
cairo_context = "Cairo_Context",
|
||||
["cairo.surface"] = "Cairo_Surface",
|
||||
color = "Color",
|
||||
client = "Client",
|
||||
["gears.shape"] = gears_shape_function,
|
||||
["gears.surface"] = "Surface",
|
||||
drawable = "Drawable",
|
||||
["gears.shape"] = "Gears_Shape_Function",
|
||||
["gears.surface"] = "Cairo_Surface",
|
||||
["Gio.InputStream"] = "any", -- We'll probably never have better support for this one, since it's a GI bindings
|
||||
image = "Image",
|
||||
int = "integer",
|
||||
Integer = "integer",
|
||||
keygrabber = "Keygrabber",
|
||||
layout = "Layout",
|
||||
["lgi.Pango.FontDescription"] = "any", -- We'll probably never have better support for this one, since it's a GI bindings
|
||||
matrix = "Matrix",
|
||||
["naughty.notification_closed_reason"] = "number", -- Teal doesn't support numeric enums
|
||||
["Pango.FontDescription"] = "any", -- We'll probably never have better support for this one, since it's a GI bindings
|
||||
placement = "Awful_Placement_Function",
|
||||
raw_surface = "Cairo_Surface",
|
||||
screen = "Screen",
|
||||
shape = gears_shape_function,
|
||||
surface = "Surface",
|
||||
shape = "Gears_Shape_Function",
|
||||
surface = "Cairo_Surface",
|
||||
tag = "Tag",
|
||||
template = "table",
|
||||
["true"] = "boolean", -- Either Teal should support literal types or maybe Awesome should use booleans instead of true
|
||||
["wibox.container"] = "table",
|
||||
["wibox.drawable"] = "Drawable",
|
||||
["wibox.layout"] = "table",
|
||||
widget = "wibox.widget",
|
||||
|
||||
-- fixes we shouldn't have to do (We need to PR Awesome to fix the doc)
|
||||
timer = "gears.timer",
|
||||
font = "string", -- doesn't exist
|
||||
func = "function", -- doesn't exist
|
||||
["gears.color"] = "any", -- shouldn't be here
|
||||
["gears.opacity"] = "number", -- error in the naughty.notification doc
|
||||
["gears.margin"] = "number", -- error in the naughty.notification doc
|
||||
gradient = "string", -- doesn't exist
|
||||
["N/A"] = "any", -- we shouldn't have to do this, what `N/A` supposed to mean?
|
||||
pattern = "string", -- doesn't exist
|
||||
raw_curface = "Cairo_Surface", -- typo
|
||||
shap = "Gears_Shape_Function", -- typo
|
||||
tale = "table", -- typo
|
||||
timer = "gears.timer", -- not resolvable
|
||||
}
|
||||
|
||||
local function get_type(t: string): string
|
||||
return type_map[t] or t
|
||||
end
|
||||
local global_type_map <const>: { string : string } = {
|
||||
screen = "screen", -- global env cannot come from another module
|
||||
}
|
||||
|
||||
local function check_node(node: Node)
|
||||
|
||||
local function check_node(node: Node, get_type: function(string): string)
|
||||
if not node.types then
|
||||
return
|
||||
end
|
||||
|
@ -35,34 +64,42 @@ local function check_node(node: Node)
|
|||
end
|
||||
end
|
||||
|
||||
local function check_function_parameters(node: Node)
|
||||
local function check_function_parameters(node: Node, get_type: function(string): string)
|
||||
if not node.parameters then
|
||||
return
|
||||
end
|
||||
|
||||
for _, parameter in ipairs(node.parameters) do
|
||||
check_node(parameter)
|
||||
check_node(parameter, get_type)
|
||||
end
|
||||
end
|
||||
|
||||
local function check_function_returns(node: Node)
|
||||
local function check_function_returns(node: Node, get_type: function(string): string)
|
||||
if not node.return_types then
|
||||
return
|
||||
end
|
||||
|
||||
for i, ret in ipairs(node.return_types) do
|
||||
node.return_types[i] = get_type(ret)
|
||||
for i, ret_ts in ipairs(node.return_types) do
|
||||
for j, t in ipairs(ret_ts) do
|
||||
node.return_types[i][j] = get_type(t)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local record Type_Mapping
|
||||
visit: function(node: Node)
|
||||
visit: function(node: Node, is_global_module: boolean)
|
||||
end
|
||||
|
||||
function Type_Mapping.visit(node: Node)
|
||||
check_node(node)
|
||||
check_function_parameters(node)
|
||||
check_function_returns(node)
|
||||
function Type_Mapping.visit(node: Node, is_global_module: boolean)
|
||||
local get_type <const> = is_global_module and function(t: string): string
|
||||
return global_type_map[t] or type_map[t] or t
|
||||
end or function(t: string): string
|
||||
return type_map[t] or t
|
||||
end
|
||||
|
||||
check_node(node, get_type)
|
||||
check_function_parameters(node, get_type)
|
||||
check_function_returns(node, get_type)
|
||||
end
|
||||
|
||||
return Type_Mapping
|
||||
|
|
Loading…
Reference in New Issue