From ebd33b0a1948674f3660c27e4747e9b08c4b92b5 Mon Sep 17 00:00:00 2001 From: Aire-One Date: Mon, 18 Sep 2023 20:04:14 +0200 Subject: [PATCH 01/40] chore(ci): add an `awesomerc.tl` validation --- .gitignore | 4 +- .vscode/settings.json | 2 + .woodpecker/build-and-run.yml | 15 + .woodpecker/build.yml | 23 -- generated/awesomerc.tl | 675 ++++++++++++++++++++++++++++++++++ generated/tlconfig.lua | 3 + justfile | 2 - src/awesomewmdtl/property.tl | 3 +- 8 files changed, 699 insertions(+), 28 deletions(-) create mode 100644 .woodpecker/build-and-run.yml delete mode 100644 .woodpecker/build.yml create mode 100644 generated/awesomerc.tl create mode 100644 generated/tlconfig.lua diff --git a/.gitignore b/.gitignore index e8da5cd..cc3ea1d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ lua_modules/ -generated/ +generated/* +!generated/awesomerc.tl +!generated/tlconfig.lua build/ luacov/ diff --git a/.vscode/settings.json b/.vscode/settings.json index 4a43426..fe95648 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -9,6 +9,7 @@ "aireone", "akorn", "ansicolors", + "awesomerc", "awesomewm", "awesomewmdtl", "buildx", @@ -45,6 +46,7 @@ "sublist", "tablex", "tbody", + "tlconfig", "tmpl", "wibox", "woodpeckerci", diff --git a/.woodpecker/build-and-run.yml b/.woodpecker/build-and-run.yml new file mode 100644 index 0000000..9059b87 --- /dev/null +++ b/.woodpecker/build-and-run.yml @@ -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 diff --git a/.woodpecker/build.yml b/.woodpecker/build.yml deleted file mode 100644 index 1bf3db0..0000000 --- a/.woodpecker/build.yml +++ /dev/null @@ -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 diff --git a/generated/awesomerc.tl b/generated/awesomerc.tl new file mode 100644 index 0000000..ae604fd --- /dev/null +++ b/generated/awesomerc.tl @@ -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) diff --git a/generated/tlconfig.lua b/generated/tlconfig.lua new file mode 100644 index 0000000..ee9f573 --- /dev/null +++ b/generated/tlconfig.lua @@ -0,0 +1,3 @@ +return { + source_dir = ".", +} diff --git a/justfile b/justfile index 6fdfa40..5fbf8d6 100644 --- a/justfile +++ b/justfile @@ -62,9 +62,7 @@ run: validate: cd generated && cyan \ check \ - --global-env-def "global_env" \ awesomerc.tl -# `find . -type f -iname '*.d.tl' | xargs` test PATTERN="_spec": luarocks \ diff --git a/src/awesomewmdtl/property.tl b/src/awesomewmdtl/property.tl index 8cbd797..099748f 100644 --- a/src/awesomewmdtl/property.tl +++ b/src/awesomewmdtl/property.tl @@ -18,9 +18,8 @@ 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 = { -- 2.40.1 From a2d172d31d175e92d968e707b67ebb78caa0f7cb Mon Sep 17 00:00:00 2001 From: Aire-One Date: Sat, 7 Oct 2023 00:25:16 +0200 Subject: [PATCH 02/40] fix(visitors): prevent circular dependencies --- src/awesomewmdtl/visitors/module_dependencies.tl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/awesomewmdtl/visitors/module_dependencies.tl b/src/awesomewmdtl/visitors/module_dependencies.tl index 24365ef..8297268 100644 --- a/src/awesomewmdtl/visitors/module_dependencies.tl +++ b/src/awesomewmdtl/visitors/module_dependencies.tl @@ -59,7 +59,9 @@ function Module_Dependencies.visit(node: Node, mod: Node, d: Dag) local dependency = d.modules[type_name] or d.modules[utils.lowercase(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 -- 2.40.1 From 086ab2a474b4fcf9f07d319d9a0537828eb773e4 Mon Sep 17 00:00:00 2001 From: Aire-One Date: Sun, 8 Oct 2023 16:48:46 +0200 Subject: [PATCH 03/40] feat(visitors): add capi_class dependencies --- .../visitors/module_dependencies.tl | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/awesomewmdtl/visitors/module_dependencies.tl b/src/awesomewmdtl/visitors/module_dependencies.tl index 8297268..be26c37 100644 --- a/src/awesomewmdtl/visitors/module_dependencies.tl +++ b/src/awesomewmdtl/visitors/module_dependencies.tl @@ -4,6 +4,23 @@ local utils = 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 : { string : Node } = { + Client = { + name = "Client", + module_path = "awful.client", + }, + 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 @@ -57,7 +74,7 @@ function Module_Dependencies.visit(node: Node, mod: Node, d: Dag) goto continue end - local dependency = d.modules[type_name] or d.modules[utils.lowercase(type_name)] + local dependency = d.modules[type_name] or d.modules[utils.lowercase(type_name)] or capi_class[type_name] if dependency then if dependency.name ~= mod.name then mod.dependencies[dependency.name] = dependency.module_path -- 2.40.1 From 989adaa62c08e3d416f29c2ea84ef1e2d4227428 Mon Sep 17 00:00:00 2001 From: Aire-One Date: Sun, 8 Oct 2023 16:59:07 +0200 Subject: [PATCH 04/40] feat: initial support to generate global_env_def --- generated/tlconfig.lua | 1 + src/awesomewmdtl/ast.tl | 6 +++-- src/awesomewmdtl/dag.tl | 7 ++++- src/awesomewmdtl/init.tl | 27 +++++++++++++++++-- .../printer/teal_type_definition.tl | 11 +++++++- src/awesomewmdtl/scraper/module_doc.tl | 4 +-- src/awesomewmdtl/types/Node.tl | 3 +++ 7 files changed, 51 insertions(+), 8 deletions(-) diff --git a/generated/tlconfig.lua b/generated/tlconfig.lua index ee9f573..ba9e02d 100644 --- a/generated/tlconfig.lua +++ b/generated/tlconfig.lua @@ -1,3 +1,4 @@ return { source_dir = ".", + global_env_def = "global_env_def", } diff --git a/src/awesomewmdtl/ast.tl b/src/awesomewmdtl/ast.tl index 1e488d4..8c693f3 100644 --- a/src/awesomewmdtl/ast.tl +++ b/src/awesomewmdtl/ast.tl @@ -1,18 +1,20 @@ local type Node = require("awesomewmdtl.types.Node") local basic_nodes : { 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 = {}, children = {}, } end, - record = function(name: string): Node + record = function(name: string, global: boolean): Node return { token = "record", + global = global, name = name, children = {}, } diff --git a/src/awesomewmdtl/dag.tl b/src/awesomewmdtl/dag.tl index 3a86ec3..7aa2443 100644 --- a/src/awesomewmdtl/dag.tl +++ b/src/awesomewmdtl/dag.tl @@ -18,13 +18,18 @@ 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 +local function iter_modules(dag: Dag): (function(): string, Node) return pairs(dag.modules) end +local function iter_global_nodes(dag: Dag): (function(): integer, Node) + return pairs(dag.global_nodes) +end + return { new = new, push_module = push_module, push_global_nodes = push_global_nodes, iter_modules = iter_modules, + iter_global_nodes = iter_global_nodes, } diff --git a/src/awesomewmdtl/init.tl b/src/awesomewmdtl/init.tl index 6459ef8..c4cf800 100644 --- a/src/awesomewmdtl/init.tl +++ b/src/awesomewmdtl/init.tl @@ -138,8 +138,24 @@ for _,root in dag.iter_modules(module_dag) do 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 : { 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 = ast.create_node("module", "global_env_def", "global_env_def", 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 @@ -159,5 +175,12 @@ for module_path, root in dag.iter_modules(module_dag) do ) end + +-- 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" +) + do_module_init_definition(module_infos) log:info("Module init files generated") diff --git a/src/awesomewmdtl/printer/teal_type_definition.tl b/src/awesomewmdtl/printer/teal_type_definition.tl index 32bfd51..dd232f3 100644 --- a/src/awesomewmdtl/printer/teal_type_definition.tl +++ b/src/awesomewmdtl/printer/teal_type_definition.tl @@ -50,6 +50,11 @@ local print_children: function(node: Node): string local node_printer : { Node.Token : Node_Printer_Function } = { ["module"] = { before_node = function(node: Node, indent_level: integer): string, integer + if node.global then + return render_code( + "-- This file was auto-generated.\n", + indent_level), indent_level + end return render_code( string.format( "-- This file was auto-generated.\n%s\nlocal record %s", @@ -61,6 +66,9 @@ local node_printer : { Node.Token : Node_Printer_Function } = { return render_code(print_children(node), indent_level), indent_level end, after_node = function(node: Node, indent_level: integer): string, integer + if node.global then + return "", indent_level + end return render_code("end", indent_level - 1) .. "\n" .. render_code( @@ -73,7 +81,8 @@ local node_printer : { 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, diff --git a/src/awesomewmdtl/scraper/module_doc.tl b/src/awesomewmdtl/scraper/module_doc.tl index 155376f..a5477ef 100644 --- a/src/awesomewmdtl/scraper/module_doc.tl +++ b/src/awesomewmdtl/scraper/module_doc.tl @@ -77,7 +77,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 @@ -262,7 +262,7 @@ function module.get_doc_from_page(html: string, module_path: string): Node, { No end local record_name = utils.capitalize((module_path:gsub(".*%.", ""))) - local module_root = ast.create_node("module", record_name, module_path) + local module_root = ast.create_node("module", record_name, module_path, false) local other_nodes : { Node } = {} local module_signals_node = ast.create_node("enum", "Signal") diff --git a/src/awesomewmdtl/types/Node.tl b/src/awesomewmdtl/types/Node.tl index fa841cc..cedfce8 100644 --- a/src/awesomewmdtl/types/Node.tl +++ b/src/awesomewmdtl/types/Node.tl @@ -24,6 +24,9 @@ local record Node -- for "module" module_path: string dependencies: { string : string } -- module_name -> module_path + + -- for "module" and "record" + global: boolean end return Node -- 2.40.1 From 544e3b5c716c6320f1921954ce97ed4320c66c62 Mon Sep 17 00:00:00 2001 From: Aire-One Date: Sun, 8 Oct 2023 17:34:16 +0200 Subject: [PATCH 05/40] feat: implement `"type"` Node type --- src/awesomewmdtl/ast.tl | 8 ++++++++ src/awesomewmdtl/init.tl | 5 +++++ .../printer/teal_type_definition.tl | 20 ++++++++++++++++--- src/awesomewmdtl/types/Node.tl | 5 +++-- 4 files changed, 33 insertions(+), 5 deletions(-) diff --git a/src/awesomewmdtl/ast.tl b/src/awesomewmdtl/ast.tl index 8c693f3..08e37a7 100644 --- a/src/awesomewmdtl/ast.tl +++ b/src/awesomewmdtl/ast.tl @@ -55,6 +55,14 @@ local basic_nodes : { 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 diff --git a/src/awesomewmdtl/init.tl b/src/awesomewmdtl/init.tl index c4cf800..05cf543 100644 --- a/src/awesomewmdtl/init.tl +++ b/src/awesomewmdtl/init.tl @@ -148,6 +148,11 @@ for _, node in dag.iter_global_nodes(module_dag) do table.insert(global_nodes_by_record_kind[record_kind], node) end local global_module_ast = ast.create_node("module", "global_env_def", "global_env_def", true) +-- Declare global types +table.insert(global_module_ast.children, ast.create_node("type", "Color", { "any" }, true)) +table.insert(global_module_ast.children, ast.create_node("type", "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)) 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 diff --git a/src/awesomewmdtl/printer/teal_type_definition.tl b/src/awesomewmdtl/printer/teal_type_definition.tl index dd232f3..a28ba05 100644 --- a/src/awesomewmdtl/printer/teal_type_definition.tl +++ b/src/awesomewmdtl/printer/teal_type_definition.tl @@ -6,11 +6,14 @@ local utils = require("awesomewmdtl.utils") local log = logger.log("scraper") -local function render_types(types: { string }): string +local function render_types(types: { string }, no_colon: boolean): string if not types or #types == 0 then return "" end - return ": " .. table.concat(types, " | ") + return string.format( + "%s%s", + no_colon and "" or ": ", + table.concat(types, " | ")) end local function dedent(str: string): string @@ -142,7 +145,18 @@ local node_printer : { Node.Token : Node_Printer_Function } = { on_node = function(): string, integer log:warn("Metamethods are not supported yet") 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, true)), + indent_level), indent_level + end, + }, } function print_teal(node: Node, indent_level: integer | nil): string diff --git a/src/awesomewmdtl/types/Node.tl b/src/awesomewmdtl/types/Node.tl index cedfce8..87f5047 100644 --- a/src/awesomewmdtl/types/Node.tl +++ b/src/awesomewmdtl/types/Node.tl @@ -7,6 +7,7 @@ local record Node "variable" "function" "metamethod" + "type" end token: Token name: string @@ -14,7 +15,7 @@ local record Node -- for "module", "record", "enum" children: { Node } - -- for "variable" + -- for "variable" and "type" types: { string } -- for "function" and "metamethod" @@ -25,7 +26,7 @@ local record Node module_path: string dependencies: { string : string } -- module_name -> module_path - -- for "module" and "record" + -- for "module", "record", "type" global: boolean end -- 2.40.1 From 93dd7e2e7be84369fb9303f8eb392ce2c4b7f7c5 Mon Sep 17 00:00:00 2001 From: Aire-One Date: Sun, 8 Oct 2023 17:35:09 +0200 Subject: [PATCH 06/40] fix: map types for `Layout` --- src/awesomewmdtl/visitors/module_dependencies.tl | 4 ++++ src/awesomewmdtl/visitors/type_mapping.tl | 1 + 2 files changed, 5 insertions(+) diff --git a/src/awesomewmdtl/visitors/module_dependencies.tl b/src/awesomewmdtl/visitors/module_dependencies.tl index be26c37..cc1b9f7 100644 --- a/src/awesomewmdtl/visitors/module_dependencies.tl +++ b/src/awesomewmdtl/visitors/module_dependencies.tl @@ -11,6 +11,10 @@ local capi_class : { string : Node } = { name = "Client", module_path = "awful.client", }, + Layout = { + name = "Layout", + module_path = "awful.layout", + }, Screen = { name = "Screen", module_path = "awful.screen", diff --git a/src/awesomewmdtl/visitors/type_mapping.tl b/src/awesomewmdtl/visitors/type_mapping.tl index 877a054..9439aae 100644 --- a/src/awesomewmdtl/visitors/type_mapping.tl +++ b/src/awesomewmdtl/visitors/type_mapping.tl @@ -11,6 +11,7 @@ local type_map : { string : string } = { ["gears.surface"] = "Surface", image = "Image", int = "integer", + layout = "Layout", screen = "Screen", shape = gears_shape_function, surface = "Surface", -- 2.40.1 From 9e65a4cc9bd99d71243db136ec9a00c3606eae0e Mon Sep 17 00:00:00 2001 From: Aire-One Date: Sun, 8 Oct 2023 17:37:16 +0200 Subject: [PATCH 07/40] feat: map more types --- src/awesomewmdtl/init.tl | 1 + src/awesomewmdtl/visitors/type_mapping.tl | 12 +++++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/awesomewmdtl/init.tl b/src/awesomewmdtl/init.tl index 05cf543..9134041 100644 --- a/src/awesomewmdtl/init.tl +++ b/src/awesomewmdtl/init.tl @@ -149,6 +149,7 @@ for _, node in dag.iter_global_nodes(module_dag) do end local global_module_ast = 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", "Surface", { "any" }, true)) table.insert(global_module_ast.children, ast.create_node("type", "Cairo_Context", { "any" }, true)) diff --git a/src/awesomewmdtl/visitors/type_mapping.tl b/src/awesomewmdtl/visitors/type_mapping.tl index 9439aae..770ab3a 100644 --- a/src/awesomewmdtl/visitors/type_mapping.tl +++ b/src/awesomewmdtl/visitors/type_mapping.tl @@ -1,19 +1,21 @@ 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 : { string : string } = { awesome = "Awesome", bool = "boolean", + ["surface._native"] = "Surface", + cairo_context = "Cairo_Context", + color = "Color", client = "Client", - ["gears.shape"] = gears_shape_function, + ["gears.shape"] = "Gears_Shape_Function", ["gears.surface"] = "Surface", image = "Image", int = "integer", layout = "Layout", + raw_surface = "Surface", + raw_curface = "Surface", -- typo that should be fixed in the Client doc screen = "Screen", - shape = gears_shape_function, + shape = "Gears_Shape_Function", surface = "Surface", tag = "Tag", widget = "wibox.widget", -- 2.40.1 From e7b938a074513617dcf957a339618986100a54a3 Mon Sep 17 00:00:00 2001 From: Aire-One Date: Sun, 8 Oct 2023 17:51:34 +0200 Subject: [PATCH 08/40] fix: prevent `Surface` vs `gears.surface` clashes --- src/awesomewmdtl/init.tl | 2 +- src/awesomewmdtl/visitors/type_mapping.tl | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/awesomewmdtl/init.tl b/src/awesomewmdtl/init.tl index 9134041..efc8da4 100644 --- a/src/awesomewmdtl/init.tl +++ b/src/awesomewmdtl/init.tl @@ -151,7 +151,7 @@ local global_module_ast = ast.create_node("module", "global_env_def", "g -- 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", "Surface", { "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)) for record_kind, nodes in pairs(global_nodes_by_record_kind) do diff --git a/src/awesomewmdtl/visitors/type_mapping.tl b/src/awesomewmdtl/visitors/type_mapping.tl index 770ab3a..4a8b595 100644 --- a/src/awesomewmdtl/visitors/type_mapping.tl +++ b/src/awesomewmdtl/visitors/type_mapping.tl @@ -3,20 +3,21 @@ local type Node = require("awesomewmdtl.types.Node") local type_map : { string : string } = { awesome = "Awesome", bool = "boolean", - ["surface._native"] = "Surface", + ["surface._native"] = "Cairo_Surface", cairo_context = "Cairo_Context", + ["cairo.surface"] = "Cairo_Surface", color = "Color", client = "Client", ["gears.shape"] = "Gears_Shape_Function", - ["gears.surface"] = "Surface", + ["gears.surface"] = "Cairo_Surface", image = "Image", int = "integer", layout = "Layout", - raw_surface = "Surface", - raw_curface = "Surface", -- typo that should be fixed in the Client doc + raw_surface = "Cairo_Surface", + raw_curface = "Cairo_Surface", -- typo that should be fixed in the Client doc screen = "Screen", shape = "Gears_Shape_Function", - surface = "Surface", + surface = "Cairo_Surface", tag = "Tag", widget = "wibox.widget", -- 2.40.1 From 59b173f774030545b5a550b02ab714c0467fb203 Mon Sep 17 00:00:00 2001 From: Aire-One Date: Sun, 12 Nov 2023 17:48:28 +0100 Subject: [PATCH 09/40] feat(visitor): add `node_fixer` --- src/awesomewmdtl/init.tl | 4 ++ src/awesomewmdtl/property.tl | 4 +- src/awesomewmdtl/visitors/node_fixer.tl | 55 +++++++++++++++++++++++++ 3 files changed, 61 insertions(+), 2 deletions(-) create mode 100644 src/awesomewmdtl/visitors/node_fixer.tl diff --git a/src/awesomewmdtl/init.tl b/src/awesomewmdtl/init.tl index efc8da4..3e52f24 100644 --- a/src/awesomewmdtl/init.tl +++ b/src/awesomewmdtl/init.tl @@ -13,6 +13,7 @@ local Map = require("pl.Map") local Module_Info = require("awesomewmdtl.entity.Module_Info") local module_dependencies = require("awesomewmdtl.visitors.module_dependencies") local type Node = require("awesomewmdtl.types.Node") +local node_fixer = require("awesomewmdtl.visitors.node_fixer") local property = require("awesomewmdtl.property") local scraper = require("awesomewmdtl.scraper") local stringx = require("pl.stringx") @@ -130,6 +131,9 @@ end -- Run the visitors for _,root in dag.iter_modules(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) end) diff --git a/src/awesomewmdtl/property.tl b/src/awesomewmdtl/property.tl index 099748f..2d7c01d 100644 --- a/src/awesomewmdtl/property.tl +++ b/src/awesomewmdtl/property.tl @@ -18,8 +18,8 @@ local record Property end local property: Property = { - base_url = "https://awesomewm.org/apidoc", - -- base_url = "file:///usr/share/doc/awesome/doc", + -- base_url = "https://awesomewm.org/apidoc", + base_url = "file:///usr/share/doc/awesome/doc", index_uri = "/index.html", out_directory = "generated", capi_modules = { diff --git a/src/awesomewmdtl/visitors/node_fixer.tl b/src/awesomewmdtl/visitors/node_fixer.tl new file mode 100644 index 0000000..86afe02 --- /dev/null +++ b/src/awesomewmdtl/visitors/node_fixer.tl @@ -0,0 +1,55 @@ +local type Node = require("awesomewmdtl.types.Node") + +-- Teal doesn't have a `keyof` operator yet, so we have to do this manually. +-- Some keys shouldn't be changed, so we don't include them here. +local enum Node_Key + "token" + "name" + -- "children" + "types" + "parameters" + "return_types" + -- "module_path" + -- "dependencies" + -- "global" +end +-- Teal can't define nested Map types yet, so we have to define a type for the nested map. +local type New_Node = { Node_Key : any } +local type New_Node_By_Name = { string : New_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 Teal doesn't have a proper way to handle them. + +-- EVERYTHING IN HERE IS TEMPORARY AND SHOULD BE REMOVED WHEN TEAL SUPPORTS IT. +-- EVERYTHING IN HERE IS TEMPORARY AND SHOULD BE REMOVED WHEN TEAL SUPPORTS IT. +-- EVERYTHING IN HERE IS TEMPORARY AND SHOULD BE REMOVED WHEN TEAL SUPPORTS IT. + +local node_fixer : { string : New_Node_By_Name } = { + ["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" } }, + } + } + }, +} + +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 = node as { string : any } + n[k] = v + end +end + +return Node_Fixer -- 2.40.1 From 728fffc9e89a9c5c8cf650a6aa52716b4cf5d1d6 Mon Sep 17 00:00:00 2001 From: Aire-One Date: Sun, 12 Nov 2023 17:57:33 +0100 Subject: [PATCH 10/40] fixup! feat(visitor): add `node_fixer` --- src/awesomewmdtl/property.tl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/awesomewmdtl/property.tl b/src/awesomewmdtl/property.tl index 2d7c01d..099748f 100644 --- a/src/awesomewmdtl/property.tl +++ b/src/awesomewmdtl/property.tl @@ -18,8 +18,8 @@ local record Property end local property: Property = { - -- base_url = "https://awesomewm.org/apidoc", - base_url = "file:///usr/share/doc/awesome/doc", + base_url = "https://awesomewm.org/apidoc", + -- base_url = "file:///usr/share/doc/awesome/doc", index_uri = "/index.html", out_directory = "generated", capi_modules = { -- 2.40.1 From 2126752e87744bf67c62761c8879e2e14930664f Mon Sep 17 00:00:00 2001 From: Aire-One Date: Sun, 12 Nov 2023 18:41:57 +0100 Subject: [PATCH 11/40] chore: add more types and fixer --- src/awesomewmdtl/init.tl | 1 + src/awesomewmdtl/printer/teal_type_definition.tl | 12 ++++++------ src/awesomewmdtl/visitors/node_fixer.tl | 10 ++++++---- src/awesomewmdtl/visitors/type_mapping.tl | 11 +++++++++-- 4 files changed, 22 insertions(+), 12 deletions(-) diff --git a/src/awesomewmdtl/init.tl b/src/awesomewmdtl/init.tl index 3e52f24..06a73cb 100644 --- a/src/awesomewmdtl/init.tl +++ b/src/awesomewmdtl/init.tl @@ -158,6 +158,7 @@ table.insert(global_module_ast.children, ast.create_node("type", "Color", { "any 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 diff --git a/src/awesomewmdtl/printer/teal_type_definition.tl b/src/awesomewmdtl/printer/teal_type_definition.tl index a28ba05..2635ab8 100644 --- a/src/awesomewmdtl/printer/teal_type_definition.tl +++ b/src/awesomewmdtl/printer/teal_type_definition.tl @@ -6,14 +6,14 @@ local utils = require("awesomewmdtl.utils") local log = logger.log("scraper") -local function render_types(types: { string }, no_colon: boolean): string +local function render_types(types: { string }, separator: string, with_colon_prefix: boolean): string if not types or #types == 0 then return "" end return string.format( "%s%s", - no_colon and "" or ": ", - table.concat(types, " | ")) + with_colon_prefix and ": " or "", + table.concat(types, separator)) end local function dedent(str: string): string @@ -122,7 +122,7 @@ local node_printer : { 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, }, @@ -137,7 +137,7 @@ local node_printer : { Node.Token : Node_Printer_Function } = { "%s: function(%s)%s", node.name, table.concat(args, ", "), - render_types(node.return_types)), + render_types(node.return_types, ", ", true)), indent_level), indent_level end, }, @@ -153,7 +153,7 @@ local node_printer : { Node.Token : Node_Printer_Function } = { "%stype %s = %s", node.global and "\nglobal " or "", node.name, - render_types(node.types, true)), + render_types(node.types, " | ")), indent_level), indent_level end, }, diff --git a/src/awesomewmdtl/visitors/node_fixer.tl b/src/awesomewmdtl/visitors/node_fixer.tl index 86afe02..f54e350 100644 --- a/src/awesomewmdtl/visitors/node_fixer.tl +++ b/src/awesomewmdtl/visitors/node_fixer.tl @@ -18,11 +18,13 @@ local type New_Node = { Node_Key : any } local type New_Node_By_Name = { string : New_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 Teal doesn't have a proper way to handle them. +-- 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 WHEN TEAL SUPPORTS IT. --- EVERYTHING IN HERE IS TEMPORARY AND SHOULD BE REMOVED WHEN TEAL SUPPORTS IT. --- EVERYTHING IN HERE IS TEMPORARY AND SHOULD BE REMOVED WHEN TEAL SUPPORTS IT. +-- 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 : { string : New_Node_By_Name } = { ["gears.surface"] = { diff --git a/src/awesomewmdtl/visitors/type_mapping.tl b/src/awesomewmdtl/visitors/type_mapping.tl index 4a8b595..fb4193d 100644 --- a/src/awesomewmdtl/visitors/type_mapping.tl +++ b/src/awesomewmdtl/visitors/type_mapping.tl @@ -12,17 +12,24 @@ local type_map : { string : string } = { ["gears.surface"] = "Cairo_Surface", image = "Image", int = "integer", + Integer = "integer", layout = "Layout", + placement = "Awful_Placement_Function", raw_surface = "Cairo_Surface", - raw_curface = "Cairo_Surface", -- typo that should be fixed in the Client doc screen = "Screen", shape = "Gears_Shape_Function", surface = "Cairo_Surface", tag = "Tag", + template = "table", + ["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 + 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 -- 2.40.1 From fd3ba675e716a88105fb18eac35f0be3c34e783a Mon Sep 17 00:00:00 2001 From: Aire-One Date: Sun, 12 Nov 2023 20:08:51 +0100 Subject: [PATCH 12/40] chore: enable more modules and fix types --- spec/scraper/module_doc_spec.tl | 4 +++ src/awesomewmdtl/property.tl | 44 +++++++++++------------ src/awesomewmdtl/scraper/module_doc.tl | 6 +++- src/awesomewmdtl/visitors/node_fixer.tl | 20 +++++++++-- src/awesomewmdtl/visitors/type_mapping.tl | 4 +++ 5 files changed, 52 insertions(+), 26 deletions(-) diff --git a/spec/scraper/module_doc_spec.tl b/spec/scraper/module_doc_spec.tl index 23b3546..b01a74c 100644 --- a/spec/scraper/module_doc_spec.tl +++ b/spec/scraper/module_doc_spec.tl @@ -820,4 +820,8 @@ describe("Scrap documentation", function() token = "function", } })) + + + -- TODO : should parse correctly types from + -- pattern, string or gradient end) diff --git a/src/awesomewmdtl/property.tl b/src/awesomewmdtl/property.tl index 099748f..780aa30 100644 --- a/src/awesomewmdtl/property.tl +++ b/src/awesomewmdtl/property.tl @@ -34,33 +34,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", diff --git a/src/awesomewmdtl/scraper/module_doc.tl b/src/awesomewmdtl/scraper/module_doc.tl index a5477ef..97b57f7 100644 --- a/src/awesomewmdtl/scraper/module_doc.tl +++ b/src/awesomewmdtl/scraper/module_doc.tl @@ -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 diff --git a/src/awesomewmdtl/visitors/node_fixer.tl b/src/awesomewmdtl/visitors/node_fixer.tl index f54e350..04db434 100644 --- a/src/awesomewmdtl/visitors/node_fixer.tl +++ b/src/awesomewmdtl/visitors/node_fixer.tl @@ -27,14 +27,28 @@ local type New_Node_By_Name = { string : New_Node } -- EVERYTHING IN HERE IS TEMPORARY AND SHOULD BE REMOVED! local node_fixer : { string : New_Node_By_Name } = { + -- ["gears.color"] = { + -- ["to_rgba_string"] = { + -- parameters = { + -- { token = "variable", name = "color", types = { "string" } }, + -- { token = "variable", name = "fallback", types = { "string" } }, + -- }, + -- }, + -- ["change_opacity"] = { + -- parameters = { + -- { token = "variable", name = "input", types = { "string" } }, + -- { token = "variable", name = "opacity", types = { "number" } }, + -- }, + -- }, + -- }, ["gears.surface"] = { - ["apply_shape_bounding"] = { + apply_shape_bounding = { parameters = { { token = "variable", name = "draw", types = { "any" } }, { token = "variable", name = "shape", types = { "Gears_Shape_Function" } }, { token = "variable", name = "...", types = { "any" } }, - } - } + }, + }, }, } diff --git a/src/awesomewmdtl/visitors/type_mapping.tl b/src/awesomewmdtl/visitors/type_mapping.tl index fb4193d..0a295c3 100644 --- a/src/awesomewmdtl/visitors/type_mapping.tl +++ b/src/awesomewmdtl/visitors/type_mapping.tl @@ -26,6 +26,10 @@ local type_map : { string : string } = { -- fixes we shouldn't have to do (We need to PR Awesome to fix the doc) font = "string", -- doesn't exist + func = "function", -- doesn't exist + ["gears.color"] = "any", -- shouldn't be here + gradient = "string", -- doesn't exist + pattern = "string", -- doesn't exist raw_curface = "Cairo_Surface", -- typo shap = "Gears_Shape_Function", -- typo tale = "table", -- typo -- 2.40.1 From 192be3b13f11a183e7821fc0f0d952492a0bacdd Mon Sep 17 00:00:00 2001 From: Aire-One Date: Fri, 17 Nov 2023 23:18:11 +0100 Subject: [PATCH 13/40] fixup! fixup! feat(visitor): add `node_fixer` --- awesomewmdtl-dev-1.rockspec | 1 + 1 file changed, 1 insertion(+) diff --git a/awesomewmdtl-dev-1.rockspec b/awesomewmdtl-dev-1.rockspec index 430d2e6..ae1d6d9 100644 --- a/awesomewmdtl-dev-1.rockspec +++ b/awesomewmdtl-dev-1.rockspec @@ -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", -- 2.40.1 From d29d2eab24d55a7d21bf234ae83fff7ef8b64529 Mon Sep 17 00:00:00 2001 From: Aire-One Date: Fri, 17 Nov 2023 23:42:39 +0100 Subject: [PATCH 14/40] feat(scraper): ignore subfields in function parameters --- src/awesomewmdtl/scraper/module_doc.tl | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/awesomewmdtl/scraper/module_doc.tl b/src/awesomewmdtl/scraper/module_doc.tl index 97b57f7..f3c2934 100644 --- a/src/awesomewmdtl/scraper/module_doc.tl +++ b/src/awesomewmdtl/scraper/module_doc.tl @@ -54,6 +54,12 @@ local function extract_function_parameters(table_html: string, function_name: st local name = extract_node_text(name_node) local types = 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) -- 2.40.1 From 9e5820db7faa58886e6a8bc9abd5de732428b417 Mon Sep 17 00:00:00 2001 From: Aire-One Date: Sat, 2 Dec 2023 01:16:01 +0100 Subject: [PATCH 15/40] feat: Node.return_types should be a { { string } } `{ { string } }` means we now have an array of strings lists AKA 2 levels array to define unions of positional types for the return types. Basically, we can now define a function that returns something like `A | B, C | D` --- .../printer/teal_type_definition.tl | 14 ++++++++++++- src/awesomewmdtl/scraper/module_doc.tl | 20 +++++++++++++++++-- src/awesomewmdtl/types/Node.tl | 2 +- .../visitors/module_dependencies.tl | 18 ++++++++++++----- src/awesomewmdtl/visitors/type_mapping.tl | 6 ++++-- 5 files changed, 49 insertions(+), 11 deletions(-) diff --git a/src/awesomewmdtl/printer/teal_type_definition.tl b/src/awesomewmdtl/printer/teal_type_definition.tl index 2635ab8..2563d73 100644 --- a/src/awesomewmdtl/printer/teal_type_definition.tl +++ b/src/awesomewmdtl/printer/teal_type_definition.tl @@ -16,6 +16,17 @@ local function render_types(types: { string }, separator: string, with_colon_pre table.concat(types, separator)) end +local function render_function_return_types(types: { { string } }): string + if not types or #types == 0 then + return "" + end + local generated = ": " + for _, t in ipairs(types) do + generated = generated .. render_types(t, ", ") + end + return generated +end + local function dedent(str: string): string return stringx.dedent(str):sub(1, -2) end @@ -137,7 +148,8 @@ local node_printer : { Node.Token : Node_Printer_Function } = { "%s: function(%s)%s", node.name, table.concat(args, ", "), - render_types(node.return_types, ", ", true)), + render_function_return_types(node.return_types) + ), indent_level), indent_level end, }, diff --git a/src/awesomewmdtl/scraper/module_doc.tl b/src/awesomewmdtl/scraper/module_doc.tl index f3c2934..5063d99 100644 --- a/src/awesomewmdtl/scraper/module_doc.tl +++ b/src/awesomewmdtl/scraper/module_doc.tl @@ -103,8 +103,24 @@ 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 raw_types = scraper_utils.scrape( + ol_html, + "span.types .type", + extract_node_text) + + local types: { { string } } = {} + for _,raw_t in ipairs(raw_types) do + local ts: { string } = {} + for t in stringx.split(raw_t) + :filter( + function(s: string): boolean + return s ~= "or" and s ~= "," + end):iter() do + table.insert(ts, t) + end + end + return types end local function extract_property_constraints(property_constraint_node: scan.HTMLNode): { string } diff --git a/src/awesomewmdtl/types/Node.tl b/src/awesomewmdtl/types/Node.tl index 87f5047..f0bba53 100644 --- a/src/awesomewmdtl/types/Node.tl +++ b/src/awesomewmdtl/types/Node.tl @@ -20,7 +20,7 @@ local record Node -- for "function" and "metamethod" parameters: { Node } - return_types: { string } + return_types: { { string } } -- for "module" module_path: string diff --git a/src/awesomewmdtl/visitors/module_dependencies.tl b/src/awesomewmdtl/visitors/module_dependencies.tl index cc1b9f7..2564038 100644 --- a/src/awesomewmdtl/visitors/module_dependencies.tl +++ b/src/awesomewmdtl/visitors/module_dependencies.tl @@ -32,11 +32,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) @@ -59,9 +65,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 diff --git a/src/awesomewmdtl/visitors/type_mapping.tl b/src/awesomewmdtl/visitors/type_mapping.tl index 0a295c3..bcdc306 100644 --- a/src/awesomewmdtl/visitors/type_mapping.tl +++ b/src/awesomewmdtl/visitors/type_mapping.tl @@ -65,8 +65,10 @@ local function check_function_returns(node: Node) 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 -- 2.40.1 From 1595e9b834f7fb68ca367da77d7da210ac662fd1 Mon Sep 17 00:00:00 2001 From: Aire-One Date: Sat, 2 Dec 2023 01:16:29 +0100 Subject: [PATCH 16/40] chore: add more types fixes --- src/awesomewmdtl/visitors/node_fixer.tl | 43 ++++++++--------------- src/awesomewmdtl/visitors/type_mapping.tl | 3 ++ 2 files changed, 17 insertions(+), 29 deletions(-) diff --git a/src/awesomewmdtl/visitors/node_fixer.tl b/src/awesomewmdtl/visitors/node_fixer.tl index 04db434..4a4573a 100644 --- a/src/awesomewmdtl/visitors/node_fixer.tl +++ b/src/awesomewmdtl/visitors/node_fixer.tl @@ -1,21 +1,7 @@ local type Node = require("awesomewmdtl.types.Node") --- Teal doesn't have a `keyof` operator yet, so we have to do this manually. --- Some keys shouldn't be changed, so we don't include them here. -local enum Node_Key - "token" - "name" - -- "children" - "types" - "parameters" - "return_types" - -- "module_path" - -- "dependencies" - -- "global" -end -- Teal can't define nested Map types yet, so we have to define a type for the nested map. -local type New_Node = { Node_Key : any } -local type New_Node_By_Name = { string : New_Node } +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 @@ -27,20 +13,19 @@ local type New_Node_By_Name = { string : New_Node } -- EVERYTHING IN HERE IS TEMPORARY AND SHOULD BE REMOVED! local node_fixer : { string : New_Node_By_Name } = { - -- ["gears.color"] = { - -- ["to_rgba_string"] = { - -- parameters = { - -- { token = "variable", name = "color", types = { "string" } }, - -- { token = "variable", name = "fallback", types = { "string" } }, - -- }, - -- }, - -- ["change_opacity"] = { - -- parameters = { - -- { token = "variable", name = "input", types = { "string" } }, - -- { token = "variable", name = "opacity", types = { "number" } }, - -- }, - -- }, - -- }, + ["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(...: ): ... + }, + }, + }, ["gears.surface"] = { apply_shape_bounding = { parameters = { diff --git a/src/awesomewmdtl/visitors/type_mapping.tl b/src/awesomewmdtl/visitors/type_mapping.tl index bcdc306..2fc4b24 100644 --- a/src/awesomewmdtl/visitors/type_mapping.tl +++ b/src/awesomewmdtl/visitors/type_mapping.tl @@ -10,10 +10,13 @@ local type_map : { string : string } = { client = "Client", ["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", layout = "Layout", + ["lgi.Pango.FontDescription"] = "any", -- We'll probably never have better support for this one, since it's a GI bindings + ["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", -- 2.40.1 From 7f781dd9e733713b8b2343b2cde53c0db424f334 Mon Sep 17 00:00:00 2001 From: Aire-One Date: Wed, 20 Dec 2023 18:25:08 +0100 Subject: [PATCH 17/40] chore: add more types fixes --- src/awesomewmdtl/visitors/type_mapping.tl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/awesomewmdtl/visitors/type_mapping.tl b/src/awesomewmdtl/visitors/type_mapping.tl index 2fc4b24..33b2a15 100644 --- a/src/awesomewmdtl/visitors/type_mapping.tl +++ b/src/awesomewmdtl/visitors/type_mapping.tl @@ -16,6 +16,7 @@ local type_map : { string : string } = { Integer = "integer", layout = "Layout", ["lgi.Pango.FontDescription"] = "any", -- We'll probably never have better support for this one, since it's a GI bindings + ["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", @@ -31,6 +32,8 @@ local type_map : { string : string } = { 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 pattern = "string", -- doesn't exist raw_curface = "Cairo_Surface", -- typo -- 2.40.1 From 28ae4fb42add8e982f078fb85f1353ec85df6945 Mon Sep 17 00:00:00 2001 From: Aire-One Date: Wed, 20 Dec 2023 19:22:33 +0100 Subject: [PATCH 18/40] test: fix module_doc_spec --- .vscode/launch.json | 2 +- justfile | 4 ++-- spec/scraper/module_doc_spec.tl | 24 ++++++++++++++++++------ src/awesomewmdtl/scraper/module_doc.tl | 1 + 4 files changed, 22 insertions(+), 9 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index dad13e8..6b867cd 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -20,7 +20,7 @@ }, "args": [ "test", - "_spec" // Adapt to the spec to debug + "\"--pattern _spec --tags debug\"" ], "scriptFiles": ["${workspaceFolder}/**/*.tl"] } diff --git a/justfile b/justfile index 5fbf8d6..772de37 100644 --- a/justfile +++ b/justfile @@ -64,12 +64,12 @@ validate: check \ awesomerc.tl -test PATTERN="_spec": +test PARAMETERS="--pattern=_spec": luarocks \ --lua-version {{ lua_version }} \ test \ {{ rockspec_file }} \ - -- --pattern={{ PATTERN }} + -- {{ PARAMETERS }} local-test PATTERN="_spec": luarocks \ diff --git a/spec/scraper/module_doc_spec.tl b/spec/scraper/module_doc_spec.tl index b01a74c..94f5d22 100644 --- a/spec/scraper/module_doc_spec.tl +++ b/spec/scraper/module_doc_spec.tl @@ -27,6 +27,7 @@ describe("Scrap documentation", function() name = "Empty", module_path = "empty", dependencies = {}, + global = false, token = "module", })) @@ -89,6 +90,7 @@ describe("Scrap documentation", function() name = "Property_signal", module_path = "property_signal", dependencies = {}, + global = false, token = "module", })) @@ -202,6 +204,7 @@ describe("Scrap documentation", function() name = "Property_enum", module_path = "property_enum", dependencies = {}, + global = false, token = "module", })) @@ -244,6 +247,7 @@ describe("Scrap documentation", function() name = "Property_string", module_path = "property_string", dependencies = {}, + global = false, token = "module", })) @@ -311,6 +315,7 @@ describe("Scrap documentation", function() name = "Tag", module_path = "awful.tag", dependencies = {}, + global = false, token = "module", })) @@ -363,6 +368,7 @@ describe("Scrap documentation", function() name = "Signal", module_path = "signal", dependencies = {}, + global = false, token = "module", })) @@ -450,7 +456,7 @@ describe("Scrap documentation", function() token = "variable", }, }, - return_types = { "boolean" }, + return_types = { { "boolean" }}, name = "kill", token = "function", } @@ -458,10 +464,11 @@ describe("Scrap documentation", function() name = "Awesome", module_path = "awesome", dependencies = {}, + global = false, token = "module", })) - it("should produce a Record node when a function parameter is a named-parameter-table", test( + it("should produce a Record node when a function parameter is a named-parameter-table #debug", test( [[

Static module functions @@ -566,6 +573,7 @@ describe("Scrap documentation", function() } }, name = "Focused_Args", + global = false, token = "record", }, { @@ -576,7 +584,7 @@ describe("Scrap documentation", function() token = "variable", }, }, - return_types = { "screen" }, + return_types = { { "screen" }}, name = "focused", token = "function", }, @@ -584,6 +592,7 @@ describe("Scrap documentation", function() name = "Screen", module_path = "awful.screen", dependencies = {}, + global = false, token = "module", })) @@ -667,7 +676,7 @@ describe("Scrap documentation", function() token = "variable", } }, - return_types = { "table" }, + return_types = { { "table" }}, name = "crush", token = "function", } @@ -675,6 +684,7 @@ describe("Scrap documentation", function() name = "Table", module_path = "gears.table", dependencies = {}, + global = false, token = "module", })) @@ -759,7 +769,7 @@ describe("Scrap documentation", function() token = "variable", }, }, - return_types = { "table" }, + return_types = { { "table" } }, name = "tags", token = "function", }, @@ -767,6 +777,7 @@ describe("Scrap documentation", function() name = "Client", module_path = "awful.client", dependencies = {}, + global = false, token = "module", })) @@ -810,12 +821,13 @@ describe("Scrap documentation", function() name = "Client", module_path = "awful.client", dependencies = {}, + global = false, token = "module", }, { { parameters = {}, - return_types = { "integer" }, + return_types = { { "integer" } }, name = "client.instances", token = "function", } diff --git a/src/awesomewmdtl/scraper/module_doc.tl b/src/awesomewmdtl/scraper/module_doc.tl index 5063d99..51353ae 100644 --- a/src/awesomewmdtl/scraper/module_doc.tl +++ b/src/awesomewmdtl/scraper/module_doc.tl @@ -119,6 +119,7 @@ local function extract_function_return_types(ol_html: string): { { string } } end):iter() do table.insert(ts, t) end + table.insert(types, ts) end return types end -- 2.40.1 From 40610de920306083b914f5c85cae4457a269b96a Mon Sep 17 00:00:00 2001 From: Aire-One Date: Wed, 20 Dec 2023 19:23:22 +0100 Subject: [PATCH 19/40] test: fix teal_type_definition_spec --- spec/printer/teal_type_definition_spec.tl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/printer/teal_type_definition_spec.tl b/spec/printer/teal_type_definition_spec.tl index 2714ac2..5a78bf4 100644 --- a/spec/printer/teal_type_definition_spec.tl +++ b/spec/printer/teal_type_definition_spec.tl @@ -108,7 +108,7 @@ describe("Teal type definition Printer", function() token = "variable", }, }, - return_types = { "boolean" }, + return_types = { { "boolean" } }, name = "kill", token = "function", }, -- 2.40.1 From d0a898134ca3ba411104c39f896196a6e4f02f10 Mon Sep 17 00:00:00 2001 From: Aire-One Date: Wed, 20 Dec 2023 23:31:23 +0100 Subject: [PATCH 20/40] fixup! feat: Node.return_types should be a { { string } } --- spec/printer/teal_type_definition_spec.tl | 4 +- spec/scraper/module_doc_spec.tl | 52 +++++++++++++++++-- .../printer/teal_type_definition.tl | 11 ++-- src/awesomewmdtl/scraper/module_doc.tl | 16 +++--- 4 files changed, 63 insertions(+), 20 deletions(-) diff --git a/spec/printer/teal_type_definition_spec.tl b/spec/printer/teal_type_definition_spec.tl index 5a78bf4..65e3088 100644 --- a/spec/printer/teal_type_definition_spec.tl +++ b/spec/printer/teal_type_definition_spec.tl @@ -108,7 +108,7 @@ describe("Teal type definition Printer", function() token = "variable", }, }, - return_types = { { "boolean" } }, + return_types = { { "boolean" }, { "nil", "number" } }, name = "kill", token = "function", }, @@ -121,7 +121,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 diff --git a/spec/scraper/module_doc_spec.tl b/spec/scraper/module_doc_spec.tl index 94f5d22..7b7adac 100644 --- a/spec/scraper/module_doc_spec.tl +++ b/spec/scraper/module_doc_spec.tl @@ -833,7 +833,53 @@ describe("Scrap documentation", function() } })) - - -- TODO : should parse correctly types from - -- pattern, string or gradient + it("should parse function return union types and multiple return values #debug", test( + [[ +

Static module functions

+
+
+ 🔗 + awesome.load_image (name) + + -> (gears.surface, nil or string) + + +
+
+ Load an image from a given path. +

Returns:

+
    +
  1. + gears.surface + A cairo surface as light user datum. +
  2. +
  3. + nil or string + The error message, if any. +
  4. +
+
+
+ ]], + "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 = {}, + global = false, + token = "module", + })) end) diff --git a/src/awesomewmdtl/printer/teal_type_definition.tl b/src/awesomewmdtl/printer/teal_type_definition.tl index 2563d73..cd23061 100644 --- a/src/awesomewmdtl/printer/teal_type_definition.tl +++ b/src/awesomewmdtl/printer/teal_type_definition.tl @@ -20,11 +20,12 @@ local function render_function_return_types(types: { { string } }): string if not types or #types == 0 then return "" end - local generated = ": " - for _, t in ipairs(types) do - generated = generated .. render_types(t, ", ") - end - return generated + + 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 dedent(str: string): string diff --git a/src/awesomewmdtl/scraper/module_doc.tl b/src/awesomewmdtl/scraper/module_doc.tl index 51353ae..fa6e96b 100644 --- a/src/awesomewmdtl/scraper/module_doc.tl +++ b/src/awesomewmdtl/scraper/module_doc.tl @@ -104,19 +104,15 @@ local function extract_function_parameters(table_html: string, function_name: st end local function extract_function_return_types(ol_html: string): { { string } } - local raw_types = scraper_utils.scrape( + local positional_return_types = scraper_utils.find( ol_html, - "span.types .type", - extract_node_text) + "span.types") local types: { { string } } = {} - for _,raw_t in ipairs(raw_types) do + for _,prt in ipairs(positional_return_types) do local ts: { string } = {} - for t in stringx.split(raw_t) - :filter( - function(s: string): boolean - return s ~= "or" and s ~= "," - end):iter() do + 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) @@ -284,7 +280,7 @@ 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 -- 2.40.1 From 37365431b2ae6081ca9e5a4bdbdf2a87f2a74f00 Mon Sep 17 00:00:00 2001 From: Aire-One Date: Wed, 20 Dec 2023 23:36:56 +0100 Subject: [PATCH 21/40] chore: add more types fixes --- src/awesomewmdtl/visitors/type_mapping.tl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/awesomewmdtl/visitors/type_mapping.tl b/src/awesomewmdtl/visitors/type_mapping.tl index 33b2a15..d504bee 100644 --- a/src/awesomewmdtl/visitors/type_mapping.tl +++ b/src/awesomewmdtl/visitors/type_mapping.tl @@ -25,6 +25,8 @@ local type_map : { string : string } = { 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.layout"] = "table", widget = "wibox.widget", -- 2.40.1 From c09409ac1cb137ffe80a296e9bc2f00136f04ea1 Mon Sep 17 00:00:00 2001 From: Aire-One Date: Thu, 21 Dec 2023 00:09:09 +0100 Subject: [PATCH 22/40] feat: implement record's metamethod for Constructor --- .vscode/settings.json | 1 + spec/printer/teal_type_definition_spec.tl | 34 ++++++++++++++++ spec/scraper/module_doc_spec.tl | 40 ++++++++++++++++++- .../printer/teal_type_definition.tl | 20 +++++++++- src/awesomewmdtl/scraper/module_doc.tl | 7 ++-- src/awesomewmdtl/types/Node.tl | 6 +++ 6 files changed, 101 insertions(+), 7 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index fe95648..2ed59c6 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -32,6 +32,7 @@ "Luarocks", "luasec", "luasocket", + "metamethods", "mkdir", "modname", "reportfile", diff --git a/spec/printer/teal_type_definition_spec.tl b/spec/printer/teal_type_definition_spec.tl index 65e3088..af489be 100644 --- a/spec/printer/teal_type_definition_spec.tl +++ b/spec/printer/teal_type_definition_spec.tl @@ -171,4 +171,38 @@ describe("Teal type definition Printer", function() return Module ]])) + + it("should print __call metamethod", gen( + { + children = { + { + children = {}, + name = "Signal", + token = "enum", + }, + { + parameters = {}, + return_types = {}, + name = "timer", + metamethod = "__call", + token = "metamethod", + } + }, + name = "Timer", + module_path = "gears.timer", + dependencies = {}, + global = false, + token = "module", + }, + [[ + -- This file was auto-generated. + + local record Timer + enum Signal + end + metamethod __call: function() + end + + return Timer + ]])) end) diff --git a/spec/scraper/module_doc_spec.tl b/spec/scraper/module_doc_spec.tl index 7b7adac..77c27fd 100644 --- a/spec/scraper/module_doc_spec.tl +++ b/spec/scraper/module_doc_spec.tl @@ -468,7 +468,7 @@ describe("Scrap documentation", function() token = "module", })) - it("should produce a Record node when a function parameter is a named-parameter-table #debug", test( + it("should produce a Record node when a function parameter is a named-parameter-table", test( [[

Static module functions @@ -833,7 +833,7 @@ describe("Scrap documentation", function() } })) - it("should parse function return union types and multiple return values #debug", test( + it("should parse function return union types and multiple return values", test( [[

Static module functions

@@ -882,4 +882,40 @@ describe("Scrap documentation", function() global = false, token = "module", })) + + it("should produce a __call metamethod for constructor", test( + [[ +

Constructors

+
+
+ 🔗 + gears.timer {[args]} + +
+
+
+
+ ]], + "gears.timer", + { + children = { + { + children = {}, + name = "Signal", + token = "enum", + }, + { + parameters = {}, + return_types = {}, + name = "timer", + metamethod = "__call", + token = "metamethod", + } + }, + name = "Timer", + module_path = "gears.timer", + dependencies = {}, + global = false, + token = "module", + })) end) diff --git a/src/awesomewmdtl/printer/teal_type_definition.tl b/src/awesomewmdtl/printer/teal_type_definition.tl index cd23061..0009cd8 100644 --- a/src/awesomewmdtl/printer/teal_type_definition.tl +++ b/src/awesomewmdtl/printer/teal_type_definition.tl @@ -28,6 +28,11 @@ local function render_function_return_types(types: { { string } }): string 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 return stringx.dedent(str):sub(1, -2) end @@ -155,8 +160,19 @@ local node_printer : { Node.Token : Node_Printer_Function } = { 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"] = { diff --git a/src/awesomewmdtl/scraper/module_doc.tl b/src/awesomewmdtl/scraper/module_doc.tl index fa6e96b..1296ca0 100644 --- a/src/awesomewmdtl/scraper/module_doc.tl +++ b/src/awesomewmdtl/scraper/module_doc.tl @@ -234,11 +234,12 @@ end -- - Nodes that should be added to the global scope -- - Strings that should be added to the record Signals local section_scrapers : { 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 = 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 + constructor.token = "metamethod" + constructor.metamethod = "__call" end end return constructors, {}, {} diff --git a/src/awesomewmdtl/types/Node.tl b/src/awesomewmdtl/types/Node.tl index f0bba53..17b69d7 100644 --- a/src/awesomewmdtl/types/Node.tl +++ b/src/awesomewmdtl/types/Node.tl @@ -22,6 +22,12 @@ local record Node parameters: { Node } return_types: { { string } } + -- for "methamethod" + enum Metamethod + "__call" + end + metamethod: Metamethod + -- for "module" module_path: string dependencies: { string : string } -- module_name -> module_path -- 2.40.1 From ec2c7870a28055b720e063fc96ea4fc7aad1adc0 Mon Sep 17 00:00:00 2001 From: Aire-One Date: Thu, 21 Dec 2023 00:09:23 +0100 Subject: [PATCH 23/40] chore: add more types fixes --- src/awesomewmdtl/visitors/type_mapping.tl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/awesomewmdtl/visitors/type_mapping.tl b/src/awesomewmdtl/visitors/type_mapping.tl index d504bee..b0e1466 100644 --- a/src/awesomewmdtl/visitors/type_mapping.tl +++ b/src/awesomewmdtl/visitors/type_mapping.tl @@ -27,6 +27,7 @@ local type_map : { string : string } = { 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", -- 2.40.1 From c3847b43c6e37b135d00881dab52337a112f0536 Mon Sep 17 00:00:00 2001 From: Aire-One Date: Thu, 21 Dec 2023 00:24:45 +0100 Subject: [PATCH 24/40] chore: add more types fixes --- src/awesomewmdtl/visitors/node_fixer.tl | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/awesomewmdtl/visitors/node_fixer.tl b/src/awesomewmdtl/visitors/node_fixer.tl index 4a4573a..e1b0791 100644 --- a/src/awesomewmdtl/visitors/node_fixer.tl +++ b/src/awesomewmdtl/visitors/node_fixer.tl @@ -35,6 +35,14 @@ local node_fixer : { string : New_Node_By_Name } = { }, }, }, + ["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 + }, + }, + }, } local record Node_Fixer -- 2.40.1 From ac0456e70407d262192059115ea9c0317a233f86 Mon Sep 17 00:00:00 2001 From: Aire-One Date: Thu, 21 Dec 2023 00:40:11 +0100 Subject: [PATCH 25/40] fixup! feat: implement record's metamethod for Constructor --- spec/printer/teal_type_definition_spec.tl | 10 ++++++++-- spec/scraper/module_doc_spec.tl | 8 +++++++- src/awesomewmdtl/scraper/module_doc.tl | 19 ++++++++++++++----- 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/spec/printer/teal_type_definition_spec.tl b/spec/printer/teal_type_definition_spec.tl index af489be..f00f46b 100644 --- a/spec/printer/teal_type_definition_spec.tl +++ b/spec/printer/teal_type_definition_spec.tl @@ -181,7 +181,13 @@ describe("Teal type definition Printer", function() token = "enum", }, { - parameters = {}, + parameters = { + { + types = { "Timer" }, + name = "self", + token = "variable", + }, + }, return_types = {}, name = "timer", metamethod = "__call", @@ -200,7 +206,7 @@ describe("Teal type definition Printer", function() local record Timer enum Signal end - metamethod __call: function() + metamethod __call: function(self: Timer) end return Timer diff --git a/spec/scraper/module_doc_spec.tl b/spec/scraper/module_doc_spec.tl index 77c27fd..065bf6a 100644 --- a/spec/scraper/module_doc_spec.tl +++ b/spec/scraper/module_doc_spec.tl @@ -905,7 +905,13 @@ describe("Scrap documentation", function() token = "enum", }, { - parameters = {}, + parameters = { + { + types = { "Timer" }, + name = "self", + token = "variable", + }, + }, return_types = {}, name = "timer", metamethod = "__call", diff --git a/src/awesomewmdtl/scraper/module_doc.tl b/src/awesomewmdtl/scraper/module_doc.tl index 1296ca0..b60513e 100644 --- a/src/awesomewmdtl/scraper/module_doc.tl +++ b/src/awesomewmdtl/scraper/module_doc.tl @@ -221,6 +221,17 @@ 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" @@ -238,8 +249,8 @@ local section_scrapers : { Section : function(html: string, record_name: local constructors = extract_section_functions(html) for _, constructor in ipairs(constructors) do if constructor.token == "function" and constructor.name == utils.lowercase(record_name) then - constructor.token = "metamethod" - constructor.metamethod = "__call" + add_self_parameter(constructor, record_name) + transform_to_call_metamethod(constructor) end end return constructors, {}, {} @@ -256,9 +267,7 @@ local section_scrapers : { Section : function(html: string, record_name: local methods = 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, {}, {} -- 2.40.1 From 3b3ba3476fdceb37fbaca295be7df81bfde9f027 Mon Sep 17 00:00:00 2001 From: Aire-One Date: Tue, 2 Jan 2024 05:32:08 +0100 Subject: [PATCH 26/40] feat: build the DAG to resolve module's tree (refactor #61) --- spec/printer/teal_type_definition_spec.tl | 56 +++++++++++++ src/awesomewmdtl/ast.tl | 57 ++++++++++++- src/awesomewmdtl/dag.tl | 81 ++++++++++++++++++- src/awesomewmdtl/init.tl | 58 +------------ .../printer/teal_type_definition.tl | 79 ++++++++++++++---- src/awesomewmdtl/types/Dag.tl | 2 +- src/awesomewmdtl/utils.tl | 33 ++++++++ .../visitors/module_dependencies.tl | 3 +- 8 files changed, 293 insertions(+), 76 deletions(-) diff --git a/spec/printer/teal_type_definition_spec.tl b/spec/printer/teal_type_definition_spec.tl index f00f46b..9a29f58 100644 --- a/spec/printer/teal_type_definition_spec.tl +++ b/spec/printer/teal_type_definition_spec.tl @@ -211,4 +211,60 @@ describe("Teal type definition Printer", function() 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 = {}, + 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) diff --git a/src/awesomewmdtl/ast.tl b/src/awesomewmdtl/ast.tl index 08e37a7..4767559 100644 --- a/src/awesomewmdtl/ast.tl +++ b/src/awesomewmdtl/ast.tl @@ -14,7 +14,7 @@ local basic_nodes : { Node.Token : function(name: string, ...: any): Node record = function(name: string, global: boolean): Node return { token = "record", - global = global, + global = global, name = name, children = {}, } @@ -70,6 +70,40 @@ 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 + for _, child in ipairs(other.children) do + 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 @@ -77,6 +111,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) @@ -84,8 +119,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, } diff --git a/src/awesomewmdtl/dag.tl b/src/awesomewmdtl/dag.tl index 7aa2443..20be5d5 100644 --- a/src/awesomewmdtl/dag.tl +++ b/src/awesomewmdtl/dag.tl @@ -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 = require("awesomewmdtl.utils") @@ -10,26 +11,98 @@ 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 = {}, + 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 = "" + for breadcrumb in module_path:gmatch("([^%.]+)") do + current_path = current_path == "" and breadcrumb or current_path .. "." .. breadcrumb + local current: Node = nil + + if current_path == module_path then + return current + end + + for _, n in ipairs(dag.modules) do + if n.module_path == current_path then + current = n + break + end + end + if current == nil then + return nil + end + end +end + return { new = new, push_module = push_module, push_global_nodes = push_global_nodes, iter_modules = iter_modules, iter_global_nodes = iter_global_nodes, + find_module = find_module, } diff --git a/src/awesomewmdtl/init.tl b/src/awesomewmdtl/init.tl index 06a73cb..ea904cc 100644 --- a/src/awesomewmdtl/init.tl +++ b/src/awesomewmdtl/init.tl @@ -9,14 +9,12 @@ local filesystem = require("awesomewmdtl.filesystem") local printer = require("awesomewmdtl.printer") local List = require("pl.List") local logger = require("awesomewmdtl.logger") -local Map = require("pl.Map") local Module_Info = require("awesomewmdtl.entity.Module_Info") local module_dependencies = require("awesomewmdtl.visitors.module_dependencies") local type Node = require("awesomewmdtl.types.Node") local node_fixer = require("awesomewmdtl.visitors.node_fixer") local property = require("awesomewmdtl.property") local scraper = require("awesomewmdtl.scraper") -local stringx = require("pl.stringx") local type_mapping = require("awesomewmdtl.visitors.type_mapping") local utils = require("awesomewmdtl.utils") @@ -46,53 +44,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): Map> - local tree: Map> = 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 -) - 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 = 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, @@ -130,7 +81,7 @@ for module in module_infos:iter() do end -- Run the visitors -for _,root in dag.iter_modules(module_dag) do +for root in dag.iter_modules(module_dag) do ast.in_order_visitor(root, function(node: Node) node_fixer.visit(node, root) end) @@ -172,17 +123,17 @@ end -- 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 @@ -193,5 +144,4 @@ filesystem.file_writer.write( property.out_directory .. "/global_env_def.d.tl" ) -do_module_init_definition(module_infos) log:info("Module init files generated") diff --git a/src/awesomewmdtl/printer/teal_type_definition.tl b/src/awesomewmdtl/printer/teal_type_definition.tl index 0009cd8..d43c59e 100644 --- a/src/awesomewmdtl/printer/teal_type_definition.tl +++ b/src/awesomewmdtl/printer/teal_type_definition.tl @@ -6,6 +6,25 @@ local utils = require("awesomewmdtl.utils") local log = logger.log("scraper") +local GEN_TEXT = "-- This file was auto-generated.\n" + +local function get_package_descendants(node: Node): { Node } + return utils.filter( + node.children, + function(child: Node): boolean + return child.token == "module" + end + ) +end + +local function nodes_to_string_map(nodes: { Node }): { string : string } + local map : { string : string } = {} + for _, node in ipairs(nodes) do + map[node.name] = node.module_path + end + return map +end + local function render_types(types: { string }, separator: string, with_colon_prefix: boolean): string if not types or #types == 0 then return "" @@ -57,35 +76,62 @@ local function render_require(dependencies: { string : string }): string return generated end +local function render_descendant(descendants: { Node }): string + local generated = "" + for _, descendant in ipairs(descendants) do + generated = generated .. string.format("%s: %s\n", utils.lowercase(descendant.name), descendant.name) + 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 : { 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 render_code( - "-- This file was auto-generated.\n", + GEN_TEXT, indent_level), 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, + utils.pipe( + get_package_descendants, + nodes_to_string_map)(node) as { string : string } -- pipe needs to be promoted + )), -- 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 + on_node = function(node: Node, indent_level: integer, parent_token: Node.Token): string, integer + if "module" == parent_token then + return render_code( + render_descendant({ node }), + indent_level), indent_level + end return render_code(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 @@ -188,19 +234,22 @@ local node_printer : { Node.Token : Node_Printer_Function } = { }, } -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 @@ -209,7 +258,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 diff --git a/src/awesomewmdtl/types/Dag.tl b/src/awesomewmdtl/types/Dag.tl index b8719cc..36febdf 100644 --- a/src/awesomewmdtl/types/Dag.tl +++ b/src/awesomewmdtl/types/Dag.tl @@ -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 diff --git a/src/awesomewmdtl/utils.tl b/src/awesomewmdtl/utils.tl index 1c57b26..c25aa3a 100644 --- a/src/awesomewmdtl/utils.tl +++ b/src/awesomewmdtl/utils.tl @@ -13,6 +13,16 @@ function utils.has_item(t: table, item: any): any return nil end +function utils.find(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(list: { T }, predicate: function(value: T, position: integer): boolean): { T } local filtered: { T } = {} @@ -101,4 +111,27 @@ function utils.pairsByKeys(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(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 diff --git a/src/awesomewmdtl/visitors/module_dependencies.tl b/src/awesomewmdtl/visitors/module_dependencies.tl index 2564038..e5d3e37 100644 --- a/src/awesomewmdtl/visitors/module_dependencies.tl +++ b/src/awesomewmdtl/visitors/module_dependencies.tl @@ -1,4 +1,5 @@ local type Dag = require("awesomewmdtl.types.Dag") +local dag = require("awesomewmdtl.dag") local type Node = require("awesomewmdtl.types.Node") local utils = require("awesomewmdtl.utils") @@ -86,7 +87,7 @@ function Module_Dependencies.visit(node: Node, mod: Node, d: Dag) goto continue end - local dependency = d.modules[type_name] or d.modules[utils.lowercase(type_name)] or capi_class[type_name] + local dependency = dag.find_module(d, type_name) or dag.find_module(d, utils.lowercase(type_name)) or capi_class[type_name] if dependency then if dependency.name ~= mod.name then mod.dependencies[dependency.name] = dependency.module_path -- 2.40.1 From 915e089e000d9510dbbd2865321fb9d87b366d8f Mon Sep 17 00:00:00 2001 From: Aire-One Date: Tue, 2 Jan 2024 17:02:54 +0100 Subject: [PATCH 27/40] fix(visitor): module_dependencies DAG find_module --- src/awesomewmdtl/dag.tl | 24 +++++++++---------- .../visitors/module_dependencies.tl | 17 ++++++++++++- 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/src/awesomewmdtl/dag.tl b/src/awesomewmdtl/dag.tl index 20be5d5..e4c0217 100644 --- a/src/awesomewmdtl/dag.tl +++ b/src/awesomewmdtl/dag.tl @@ -78,24 +78,22 @@ 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 - local current: Node = nil - - if current_path == module_path then - return current - end - - for _, n in ipairs(dag.modules) do - if n.module_path == current_path then - current = n - break + 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 - if current == nil then - return nil - end + break + ::continue:: end + return nil end return { diff --git a/src/awesomewmdtl/visitors/module_dependencies.tl b/src/awesomewmdtl/visitors/module_dependencies.tl index e5d3e37..c6a164b 100644 --- a/src/awesomewmdtl/visitors/module_dependencies.tl +++ b/src/awesomewmdtl/visitors/module_dependencies.tl @@ -86,8 +86,23 @@ 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 + if capi_class[type_name] then + goto continue + end - local dependency = dag.find_module(d, type_name) or dag.find_module(d, utils.lowercase(type_name)) or capi_class[type_name] + local dependency = dag.find_module(d, type_name) if dependency then if dependency.name ~= mod.name then mod.dependencies[dependency.name] = dependency.module_path -- 2.40.1 From 879abd00a6031e94f5483a03c883995116799074 Mon Sep 17 00:00:00 2001 From: Aire-One Date: Tue, 2 Jan 2024 17:12:55 +0100 Subject: [PATCH 28/40] fixup! fix(visitor): module_dependencies DAG find_module --- src/awesomewmdtl/visitors/module_dependencies.tl | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/awesomewmdtl/visitors/module_dependencies.tl b/src/awesomewmdtl/visitors/module_dependencies.tl index c6a164b..931f6f4 100644 --- a/src/awesomewmdtl/visitors/module_dependencies.tl +++ b/src/awesomewmdtl/visitors/module_dependencies.tl @@ -98,11 +98,8 @@ function Module_Dependencies.visit(node: Node, mod: Node, d: Dag) }, type_name) then goto continue end - if capi_class[type_name] then - goto continue - end - local dependency = dag.find_module(d, type_name) + local dependency = dag.find_module(d, type_name) or capi_class[type_name] if dependency then if dependency.name ~= mod.name then mod.dependencies[dependency.name] = dependency.module_path -- 2.40.1 From 577bb6373d896466610631fec363b5daffde342b Mon Sep 17 00:00:00 2001 From: Aire-One Date: Tue, 2 Jan 2024 18:25:05 +0100 Subject: [PATCH 29/40] feat(visitor): implement module_descendants --- spec/printer/teal_type_definition_spec.tl | 10 ++++++ spec/scraper/module_doc_spec.tl | 13 +++++++ src/awesomewmdtl/ast.tl | 1 + src/awesomewmdtl/init.tl | 4 +++ .../printer/teal_type_definition.tl | 22 +----------- src/awesomewmdtl/types/Node.tl | 1 + .../visitors/module_descendants.tl | 35 +++++++++++++++++++ 7 files changed, 65 insertions(+), 21 deletions(-) create mode 100644 src/awesomewmdtl/visitors/module_descendants.tl diff --git a/spec/printer/teal_type_definition_spec.tl b/spec/printer/teal_type_definition_spec.tl index 9a29f58..7751892 100644 --- a/spec/printer/teal_type_definition_spec.tl +++ b/spec/printer/teal_type_definition_spec.tl @@ -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", }, @@ -114,6 +117,7 @@ describe("Teal type definition Printer", function() }, }, dependencies = {}, + descendants = {}, name = "Function_Module", token = "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", }, @@ -197,6 +203,7 @@ describe("Teal type definition Printer", function() name = "Timer", module_path = "gears.timer", dependencies = {}, + descendants = {}, global = false, token = "module", }, @@ -251,6 +258,9 @@ describe("Teal type definition Printer", function() name = "Widget", module_path = "wibox.widget", dependencies = {}, + descendants = { + Imagebox = "wibox.widget.imagebox", + }, global = false, token = "module", }, diff --git a/spec/scraper/module_doc_spec.tl b/spec/scraper/module_doc_spec.tl index 065bf6a..a70f017 100644 --- a/spec/scraper/module_doc_spec.tl +++ b/spec/scraper/module_doc_spec.tl @@ -27,6 +27,7 @@ describe("Scrap documentation", function() name = "Empty", module_path = "empty", dependencies = {}, + descendants = {}, global = false, token = "module", })) @@ -90,6 +91,7 @@ describe("Scrap documentation", function() name = "Property_signal", module_path = "property_signal", dependencies = {}, + descendants = {}, global = false, token = "module", })) @@ -204,6 +206,7 @@ describe("Scrap documentation", function() name = "Property_enum", module_path = "property_enum", dependencies = {}, + descendants = {}, global = false, token = "module", })) @@ -247,6 +250,7 @@ describe("Scrap documentation", function() name = "Property_string", module_path = "property_string", dependencies = {}, + descendants = {}, global = false, token = "module", })) @@ -315,6 +319,7 @@ describe("Scrap documentation", function() name = "Tag", module_path = "awful.tag", dependencies = {}, + descendants = {}, global = false, token = "module", })) @@ -368,6 +373,7 @@ describe("Scrap documentation", function() name = "Signal", module_path = "signal", dependencies = {}, + descendants = {}, global = false, token = "module", })) @@ -464,6 +470,7 @@ describe("Scrap documentation", function() name = "Awesome", module_path = "awesome", dependencies = {}, + descendants = {}, global = false, token = "module", })) @@ -592,6 +599,7 @@ describe("Scrap documentation", function() name = "Screen", module_path = "awful.screen", dependencies = {}, + descendants = {}, global = false, token = "module", })) @@ -684,6 +692,7 @@ describe("Scrap documentation", function() name = "Table", module_path = "gears.table", dependencies = {}, + descendants = {}, global = false, token = "module", })) @@ -777,6 +786,7 @@ describe("Scrap documentation", function() name = "Client", module_path = "awful.client", dependencies = {}, + descendants = {}, global = false, token = "module", })) @@ -821,6 +831,7 @@ describe("Scrap documentation", function() name = "Client", module_path = "awful.client", dependencies = {}, + descendants = {}, global = false, token = "module", }, @@ -879,6 +890,7 @@ describe("Scrap documentation", function() name = "Awesome", module_path = "awesome", dependencies = {}, + descendants = {}, global = false, token = "module", })) @@ -921,6 +933,7 @@ describe("Scrap documentation", function() name = "Timer", module_path = "gears.timer", dependencies = {}, + descendants = {}, global = false, token = "module", })) diff --git a/src/awesomewmdtl/ast.tl b/src/awesomewmdtl/ast.tl index 4767559..b65c517 100644 --- a/src/awesomewmdtl/ast.tl +++ b/src/awesomewmdtl/ast.tl @@ -8,6 +8,7 @@ local basic_nodes : { Node.Token : function(name: string, ...: any): Node name = name, module_path = module_path, dependencies = {}, + descendants = {}, children = {}, } end, diff --git a/src/awesomewmdtl/init.tl b/src/awesomewmdtl/init.tl index ea904cc..7a89010 100644 --- a/src/awesomewmdtl/init.tl +++ b/src/awesomewmdtl/init.tl @@ -11,6 +11,7 @@ local List = require("pl.List") local logger = require("awesomewmdtl.logger") local Module_Info = require("awesomewmdtl.entity.Module_Info") local module_dependencies = require("awesomewmdtl.visitors.module_dependencies") +local module_descendants = require("awesomewmdtl.visitors.module_descendants") local type Node = require("awesomewmdtl.types.Node") local node_fixer = require("awesomewmdtl.visitors.node_fixer") local property = require("awesomewmdtl.property") @@ -91,6 +92,9 @@ for root in dag.iter_modules(module_dag) do 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_env_def.d.tl module from module_dag.global_nodes diff --git a/src/awesomewmdtl/printer/teal_type_definition.tl b/src/awesomewmdtl/printer/teal_type_definition.tl index d43c59e..882596a 100644 --- a/src/awesomewmdtl/printer/teal_type_definition.tl +++ b/src/awesomewmdtl/printer/teal_type_definition.tl @@ -8,23 +8,6 @@ local log = logger.log("scraper") local GEN_TEXT = "-- This file was auto-generated.\n" -local function get_package_descendants(node: Node): { Node } - return utils.filter( - node.children, - function(child: Node): boolean - return child.token == "module" - end - ) -end - -local function nodes_to_string_map(nodes: { Node }): { string : string } - local map : { string : string } = {} - for _, node in ipairs(nodes) do - map[node.name] = node.module_path - end - return map -end - local function render_types(types: { string }, separator: string, with_colon_prefix: boolean): string if not types or #types == 0 then return "" @@ -113,10 +96,7 @@ local node_printer : { Node.Token : Node_Printer_Function } = { render_require( utils.merge_map( node.dependencies, - utils.pipe( - get_package_descendants, - nodes_to_string_map)(node) as { string : string } -- pipe needs to be promoted - )), -- last require statement will have a newline + node.descendants)), -- last require statement will have a newline node.name), indent_level), indent_level + 1 end, diff --git a/src/awesomewmdtl/types/Node.tl b/src/awesomewmdtl/types/Node.tl index 17b69d7..e8a1bd9 100644 --- a/src/awesomewmdtl/types/Node.tl +++ b/src/awesomewmdtl/types/Node.tl @@ -31,6 +31,7 @@ local record Node -- 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 diff --git a/src/awesomewmdtl/visitors/module_descendants.tl b/src/awesomewmdtl/visitors/module_descendants.tl new file mode 100644 index 0000000..a0d88e6 --- /dev/null +++ b/src/awesomewmdtl/visitors/module_descendants.tl @@ -0,0 +1,35 @@ +local type Node = require("awesomewmdtl.types.Node") + +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[descendant.name] then + descendants_by_name[descendant.name] = nil + end + end + + node.descendants = descendants_by_name +end + +return Module_Descendants -- 2.40.1 From e83018f54569d3a063f46898f84fde606969f669 Mon Sep 17 00:00:00 2001 From: Aire-One Date: Tue, 2 Jan 2024 18:25:46 +0100 Subject: [PATCH 30/40] chore: add more types fixes --- src/awesomewmdtl/visitors/node_fixer.tl | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/awesomewmdtl/visitors/node_fixer.tl b/src/awesomewmdtl/visitors/node_fixer.tl index e1b0791..22bc61d 100644 --- a/src/awesomewmdtl/visitors/node_fixer.tl +++ b/src/awesomewmdtl/visitors/node_fixer.tl @@ -26,6 +26,11 @@ local node_fixer : { string : New_Node_By_Name } = { }, }, }, + ["gears.filesystem"] = { + get_themes_dir = { + return_types = { { "string" } }, -- The Awesome APIDoc have to updated + }, + }, ["gears.surface"] = { apply_shape_bounding = { parameters = { -- 2.40.1 From d87a1f93eb2f1cd06ab8496f128b2037a4a0bf66 Mon Sep 17 00:00:00 2001 From: Aire-One Date: Tue, 2 Jan 2024 18:41:01 +0100 Subject: [PATCH 31/40] feat: allow declaration of global modules --- src/awesomewmdtl/init.tl | 19 +++++++++++++++++++ .../printer/teal_type_definition.tl | 4 +--- src/awesomewmdtl/property.tl | 4 +--- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/awesomewmdtl/init.tl b/src/awesomewmdtl/init.tl index 7a89010..3502010 100644 --- a/src/awesomewmdtl/init.tl +++ b/src/awesomewmdtl/init.tl @@ -97,6 +97,25 @@ for root in dag.iter_modules(module_dag) do end) 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 + -- Build the global_env_def.d.tl module from module_dag.global_nodes local global_nodes_by_record_kind : { string : { Node } } = {} for _, node in dag.iter_global_nodes(module_dag) do diff --git a/src/awesomewmdtl/printer/teal_type_definition.tl b/src/awesomewmdtl/printer/teal_type_definition.tl index 882596a..d37e81b 100644 --- a/src/awesomewmdtl/printer/teal_type_definition.tl +++ b/src/awesomewmdtl/printer/teal_type_definition.tl @@ -85,9 +85,7 @@ local node_printer : { Node.Token : Node_Printer_Function } = { return "", indent_level end if node.global then - return render_code( - GEN_TEXT, - indent_level), indent_level + return "", indent_level end return render_code( string.format( diff --git a/src/awesomewmdtl/property.tl b/src/awesomewmdtl/property.tl index 780aa30..7e39e08 100644 --- a/src/awesomewmdtl/property.tl +++ b/src/awesomewmdtl/property.tl @@ -24,9 +24,7 @@ local property: Property = { out_directory = "generated", capi_modules = { "awesome", - "client and awful.client", - "screen and awful.screen", - "tag and awful.tag", + "drawable", }, ignored_modules = { -- Sample files -- 2.40.1 From 57a3c1bc407f2afd29e7ea987936cd922507b8a3 Mon Sep 17 00:00:00 2001 From: Aire-One Date: Tue, 2 Jan 2024 20:11:32 +0100 Subject: [PATCH 32/40] fix(module_descendants): prevent adding a children that already exists --- src/awesomewmdtl/dag.tl | 1 + .../printer/teal_type_definition.tl | 17 ++++++++++------- src/awesomewmdtl/visitors/module_descendants.tl | 7 +++++-- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/awesomewmdtl/dag.tl b/src/awesomewmdtl/dag.tl index e4c0217..bf064f0 100644 --- a/src/awesomewmdtl/dag.tl +++ b/src/awesomewmdtl/dag.tl @@ -42,6 +42,7 @@ local function push_module(dag: Dag, module_path: string, node: Node) name = utils.capitalize(breadcrumb), module_path = current_path, dependencies = {}, + descendants = {}, token = "module", } push_module(dag, current_path, current) diff --git a/src/awesomewmdtl/printer/teal_type_definition.tl b/src/awesomewmdtl/printer/teal_type_definition.tl index d37e81b..9b56832 100644 --- a/src/awesomewmdtl/printer/teal_type_definition.tl +++ b/src/awesomewmdtl/printer/teal_type_definition.tl @@ -59,10 +59,10 @@ local function render_require(dependencies: { string : string }): string return generated end -local function render_descendant(descendants: { Node }): string +local function render_descendant(descendants: { string : string }): string local generated = "" - for _, descendant in ipairs(descendants) do - generated = generated .. string.format("%s: %s\n", utils.lowercase(descendant.name), descendant.name) + for descendant in utils.pairsByKeys(descendants) do + generated = generated .. string.format("%s: %s\n", utils.lowercase(descendant), descendant) end return generated end @@ -100,11 +100,14 @@ local node_printer : { Node.Token : Node_Printer_Function } = { end, on_node = function(node: Node, indent_level: integer, parent_token: Node.Token): string, integer if "module" == parent_token then - return render_code( - render_descendant({ node }), - indent_level), indent_level + return "", indent_level end - return render_code(print_children(node), indent_level), indent_level + 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, parent_token: Node.Token): string, integer if "module" == parent_token then diff --git a/src/awesomewmdtl/visitors/module_descendants.tl b/src/awesomewmdtl/visitors/module_descendants.tl index a0d88e6..949748a 100644 --- a/src/awesomewmdtl/visitors/module_descendants.tl +++ b/src/awesomewmdtl/visitors/module_descendants.tl @@ -1,4 +1,7 @@ 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 } = {} @@ -24,8 +27,8 @@ function Module_Descendants.visit(node: Node) local descendants_by_name = get_descendants_module(node) for _, descendant in ipairs(node.children) do - if descendant.token ~= "module" and descendants_by_name[descendant.name] then - descendants_by_name[descendant.name] = nil + if descendant.token ~= "module" and descendants_by_name[capitalize(descendant.name)] then + descendants_by_name[capitalize(descendant.name)] = nil end end -- 2.40.1 From 4f67316879611f5cca6cb894c2777b53331767fc Mon Sep 17 00:00:00 2001 From: Aire-One Date: Tue, 2 Jan 2024 20:12:10 +0100 Subject: [PATCH 33/40] fix(ast): correctly merge children --- src/awesomewmdtl/ast.tl | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/awesomewmdtl/ast.tl b/src/awesomewmdtl/ast.tl index b65c517..039e267 100644 --- a/src/awesomewmdtl/ast.tl +++ b/src/awesomewmdtl/ast.tl @@ -95,7 +95,14 @@ local function merge_nodes(node: Node, other: Node): Node 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 -- 2.40.1 From 1a75a7fa8183a36f82dc3c2f970034e13a1dbad6 Mon Sep 17 00:00:00 2001 From: Aire-One Date: Sun, 25 Feb 2024 15:29:38 +0100 Subject: [PATCH 34/40] fix(type_mapping): run visitors on global_env and specialize type_mapping --- src/awesomewmdtl/init.tl | 41 ++++++++++++++--------- src/awesomewmdtl/visitors/type_mapping.tl | 31 ++++++++++------- 2 files changed, 44 insertions(+), 28 deletions(-) diff --git a/src/awesomewmdtl/init.tl b/src/awesomewmdtl/init.tl index 3502010..0771000 100644 --- a/src/awesomewmdtl/init.tl +++ b/src/awesomewmdtl/init.tl @@ -81,22 +81,6 @@ for module in module_infos:iter() do dag.push_global_nodes(module_dag, other_nodes) end --- Run the visitors -for root in dag.iter_modules(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) - 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 - -- Push global nodes to the global module for _, mod in ipairs(property.capi_modules) do local node: Node = nil @@ -116,6 +100,31 @@ for _, mod in ipairs(property.capi_modules) do end end +-- Run the visitors +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) + 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_env_def.d.tl module from module_dag.global_nodes local global_nodes_by_record_kind : { string : { Node } } = {} for _, node in dag.iter_global_nodes(module_dag) do diff --git a/src/awesomewmdtl/visitors/type_mapping.tl b/src/awesomewmdtl/visitors/type_mapping.tl index b0e1466..cb6c932 100644 --- a/src/awesomewmdtl/visitors/type_mapping.tl +++ b/src/awesomewmdtl/visitors/type_mapping.tl @@ -45,11 +45,12 @@ local type_map : { string : string } = { timer = "gears.timer", -- not resolvable } -local function get_type(t: string): string - return type_map[t] or t -end +local global_type_map : { 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 @@ -59,17 +60,17 @@ 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 @@ -82,13 +83,19 @@ local function check_function_returns(node: Node) 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 = 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 -- 2.40.1 From 4b8e32e3da04cb7899dc882f7fec36630df70a50 Mon Sep 17 00:00:00 2001 From: Aire-One Date: Sun, 25 Feb 2024 16:22:40 +0100 Subject: [PATCH 35/40] chore: add more types fixes --- src/awesomewmdtl/visitors/node_fixer.tl | 79 +++++++++++++++++++++++ src/awesomewmdtl/visitors/type_mapping.tl | 3 +- 2 files changed, 81 insertions(+), 1 deletion(-) diff --git a/src/awesomewmdtl/visitors/node_fixer.tl b/src/awesomewmdtl/visitors/node_fixer.tl index 22bc61d..7965433 100644 --- a/src/awesomewmdtl/visitors/node_fixer.tl +++ b/src/awesomewmdtl/visitors/node_fixer.tl @@ -31,6 +31,14 @@ local node_fixer : { string : New_Node_By_Name } = { 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 = { @@ -48,6 +56,77 @@ local node_fixer : { string : New_Node_By_Name } = { }, }, }, + ["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(...: ): + }, + }, + }, + ["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 diff --git a/src/awesomewmdtl/visitors/type_mapping.tl b/src/awesomewmdtl/visitors/type_mapping.tl index cb6c932..7c88e5b 100644 --- a/src/awesomewmdtl/visitors/type_mapping.tl +++ b/src/awesomewmdtl/visitors/type_mapping.tl @@ -1,13 +1,14 @@ local type Node = require("awesomewmdtl.types.Node") local type_map : { string : string } = { - awesome = "Awesome", + Awesome = "awesome", bool = "boolean", ["surface._native"] = "Cairo_Surface", cairo_context = "Cairo_Context", ["cairo.surface"] = "Cairo_Surface", color = "Color", client = "Client", + 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 -- 2.40.1 From 8d3832499a07cec39e9fa43eab10dd090068bd94 Mon Sep 17 00:00:00 2001 From: Aire-One Date: Sun, 25 Feb 2024 16:35:10 +0100 Subject: [PATCH 36/40] fix: make global_env awesome lowercase --- src/awesomewmdtl/scraper/module_doc.tl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/awesomewmdtl/scraper/module_doc.tl b/src/awesomewmdtl/scraper/module_doc.tl index b60513e..ea06009 100644 --- a/src/awesomewmdtl/scraper/module_doc.tl +++ b/src/awesomewmdtl/scraper/module_doc.tl @@ -294,7 +294,9 @@ function module.get_doc_from_page(html: string, module_path: string): Node, { No error "The list aren't the same size!" end - local record_name = utils.capitalize((module_path:gsub(".*%.", ""))) + -- 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 = module_path == "awesome" and "awesome" or utils.capitalize((module_path:gsub(".*%.", ""))) local module_root = ast.create_node("module", record_name, module_path, false) local other_nodes : { Node } = {} -- 2.40.1 From 2e2e74745dbadb70e0ef998a79b739e98487acb4 Mon Sep 17 00:00:00 2001 From: Aire-One Date: Sun, 25 Feb 2024 19:04:25 +0100 Subject: [PATCH 37/40] feat(scraper): implement `"Fields"` section type --- spec/scraper/module_doc_spec.tl | 35 ++++++++++++++++++++++++++ src/awesomewmdtl/scraper/module_doc.tl | 25 +++++++++++------- 2 files changed, 51 insertions(+), 9 deletions(-) diff --git a/spec/scraper/module_doc_spec.tl b/spec/scraper/module_doc_spec.tl index a70f017..5ee053c 100644 --- a/spec/scraper/module_doc_spec.tl +++ b/spec/scraper/module_doc_spec.tl @@ -937,4 +937,39 @@ describe("Scrap documentation", function() global = false, token = "module", })) + + it("should produce Variable for content in the Fields section", test( + [[ +

Fields

+
+
+ 🔗 + screen.primary + screen + +
+
+
+ ]], + "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) diff --git a/src/awesomewmdtl/scraper/module_doc.tl b/src/awesomewmdtl/scraper/module_doc.tl index ea06009..fb85cbc 100644 --- a/src/awesomewmdtl/scraper/module_doc.tl +++ b/src/awesomewmdtl/scraper/module_doc.tl @@ -34,7 +34,7 @@ local function extract_item_name(item_name_node: scan.HTMLNode): string, string end local module_name_node = 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 = item_name_node:inner_text():gsub("^.*[%.:](.+)%s*[%(%{].*[%)%}]", "%1") + local name = 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 @@ -174,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 : { 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 : { Node } = {} @@ -194,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 = 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 }) @@ -235,6 +237,7 @@ end local enum Section "Constructors" "Static module functions" + "Fields" "Object properties" "Object methods" "Signals" @@ -259,8 +262,12 @@ local section_scrapers : { 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 } -- 2.40.1 From 8cfb6f887e787f6265a6fb50ade828718e5f49e2 Mon Sep 17 00:00:00 2001 From: Aire-One Date: Sun, 25 Feb 2024 19:06:46 +0100 Subject: [PATCH 38/40] fixup! fix: make global_env awesome lowercase --- spec/scraper/module_doc_spec.tl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/scraper/module_doc_spec.tl b/spec/scraper/module_doc_spec.tl index 5ee053c..4de889b 100644 --- a/spec/scraper/module_doc_spec.tl +++ b/spec/scraper/module_doc_spec.tl @@ -467,7 +467,7 @@ describe("Scrap documentation", function() token = "function", } }, - name = "Awesome", + name = "awesome", module_path = "awesome", dependencies = {}, descendants = {}, @@ -887,7 +887,7 @@ describe("Scrap documentation", function() token = "function", } }, - name = "Awesome", + name = "awesome", module_path = "awesome", dependencies = {}, descendants = {}, -- 2.40.1 From 35c904c16d2a74738231254d865655bb6e591dcc Mon Sep 17 00:00:00 2001 From: Aire-One Date: Sun, 25 Feb 2024 19:31:51 +0100 Subject: [PATCH 39/40] feat(visitors): implement remove_duplicate_fields --- src/awesomewmdtl/init.tl | 4 +++ .../visitors/remove_duplicate_fields.tl | 31 +++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 src/awesomewmdtl/visitors/remove_duplicate_fields.tl diff --git a/src/awesomewmdtl/init.tl b/src/awesomewmdtl/init.tl index 0771000..726faaa 100644 --- a/src/awesomewmdtl/init.tl +++ b/src/awesomewmdtl/init.tl @@ -15,6 +15,7 @@ local module_descendants = require("awesomewmdtl.visitors.module_descend local type Node = require("awesomewmdtl.types.Node") local node_fixer = require("awesomewmdtl.visitors.node_fixer") local property = require("awesomewmdtl.property") +local remove_duplicate_fields = require("awesomewmdtl.visitors.remove_duplicate_fields") local scraper = require("awesomewmdtl.scraper") local type_mapping = require("awesomewmdtl.visitors.type_mapping") local utils = require("awesomewmdtl.utils") @@ -111,6 +112,9 @@ for _,root in dag.iter_global_nodes(module_dag) do 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) diff --git a/src/awesomewmdtl/visitors/remove_duplicate_fields.tl b/src/awesomewmdtl/visitors/remove_duplicate_fields.tl new file mode 100644 index 0000000..9300052 --- /dev/null +++ b/src/awesomewmdtl/visitors/remove_duplicate_fields.tl @@ -0,0 +1,31 @@ +local type Node = require("awesomewmdtl.types.Node") +local utils = require("awesomewmdtl.utils") + +local has_item = 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 -- 2.40.1 From 8a97241c675a5174a388a482db5aab21d010144c Mon Sep 17 00:00:00 2001 From: Aire-One Date: Sun, 25 Feb 2024 19:32:16 +0100 Subject: [PATCH 40/40] chore: add more types fixes --- src/awesomewmdtl/visitors/type_mapping.tl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/awesomewmdtl/visitors/type_mapping.tl b/src/awesomewmdtl/visitors/type_mapping.tl index 7c88e5b..260c2f0 100644 --- a/src/awesomewmdtl/visitors/type_mapping.tl +++ b/src/awesomewmdtl/visitors/type_mapping.tl @@ -15,8 +15,10 @@ local type_map : { string : string } = { 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", @@ -39,6 +41,7 @@ local type_map : { string : string } = { ["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 -- 2.40.1