diff --git a/objects/client.c b/objects/client.c index 3ca5efd58..f929e2bf9 100644 --- a/objects/client.c +++ b/objects/client.c @@ -82,6 +82,8 @@ * To get all the clients for a screen use either `screen.clients` or * `screen.tiled_clients`. * + * @DOC_uml_nav_tables_client_EXAMPLE@ + * * @author Julien Danjou <julien@danjou.info> * @copyright 2008-2009 Julien Danjou * @coreclassmod client @@ -129,7 +131,7 @@ * it is only useful when setting or getting these properties require code to * executed. * - * @table awful.object + * @table awful.client.object */ /** AwesomeWM is about to scan for existing clients. diff --git a/objects/screen.c b/objects/screen.c index f4510215c..22df006a4 100644 --- a/objects/screen.c +++ b/objects/screen.c @@ -40,6 +40,8 @@ * Furthermore to the classes described here, one can also use signals as * described in @{signals}. * + * @DOC_uml_nav_tables_screen_EXAMPLE@ + * * @author Julien Danjou <julien@danjou.info> * @copyright 2008-2009 Julien Danjou * @coreclassmod screen diff --git a/objects/tag.c b/objects/tag.c index 401a66a57..3f0dd75b8 100644 --- a/objects/tag.c +++ b/objects/tag.c @@ -178,6 +178,8 @@ * the documentation generation, you get the real signal name by * removing the starting dot. * + * @DOC_uml_nav_tables_tag_EXAMPLE@ + * * @author Julien Danjou <julien@danjou.info> * @copyright 2008-2009 Julien Danjou * @coreclassmod tag diff --git a/tests/examples/CMakeLists.txt b/tests/examples/CMakeLists.txt index c4eef2552..3d2a81ed6 100644 --- a/tests/examples/CMakeLists.txt +++ b/tests/examples/CMakeLists.txt @@ -232,15 +232,23 @@ function(run_test test_path namespace escaped_content) file(READ "${expected_output_path}" expected_output) endif() - set(TEST_DOC_CONTENT - "${TEST_DOC_CONTENT}\n${DOC_LINE_PREFIX}\n${DOC_LINE_PREFIX}**Usage example output**:\n${DOC_LINE_PREFIX}" - ) + if (NOT tmp_content MATCHES "--DOC_RAW_OUTPUT") + set(TEST_DOC_CONTENT + "${TEST_DOC_CONTENT}\n${DOC_LINE_PREFIX}\n${DOC_LINE_PREFIX}**Usage example output**:\n${DOC_LINE_PREFIX}" + ) + + # Markdown requires an empty line before and after, and 4 spaces. + escape_string( + "\n${expected_output}" + "${TEST_DOC_CONTENT}" TEST_DOC_CONTENT " " + ) + else() + escape_string( + "\n${expected_output}" + "${TEST_DOC_CONTENT}" TEST_DOC_CONTENT "" + ) + endif() - # Markdown requires an empty line before and after, and 4 spaces. - escape_string( - "\n${expected_output}" - "${TEST_DOC_CONTENT}" TEST_DOC_CONTENT " " - ) set(TEST_DOC_CONTENT "${TEST_DOC_CONTENT}\n${DOC_LINE_PREFIX}") endif() @@ -270,14 +278,31 @@ function(run_test test_path namespace escaped_content) if(NOT ${OUTPUT_IMAGE_PATH} STREQUAL "") file(RELATIVE_PATH rel_output "${TOP_SOURCE_DIR}" "${OUTPUT_IMAGE_PATH}") - add_custom_command( - COMMAND "${TOP_SOURCE_DIR}/tests/examples/runner.sh" "${expected_output_path}" ${LUA_COV_RUNNER} ${template} ${test_path} ${IMAGE_PATH} ${IGNORE_ERRORS} - # COMMENT "Running ${rel_test_path} (via ${rel_template}, generating ${rel_output})" - DEPENDS ${template} ${test_path} - OUTPUT ${OUTPUT_IMAGE_PATH} - VERBATIM) + if(tmp_content MATCHES "--DOC_GEN_OUTPUT") + add_custom_command( + COMMAND "${TOP_SOURCE_DIR}/tests/examples/runner.sh" "${expected_output_path}" ${LUA_COV_RUNNER} ${template} ${test_path} ${IMAGE_PATH} ${IGNORE_ERRORS} + # COMMENT "Running ${rel_test_path} (via ${rel_template}, generating ${rel_output})" + DEPENDS ${template} ${test_path} + OUTPUT ${OUTPUT_IMAGE_PATH} + OUTPUT ${expected_output_path} + VERBATIM) + else() + add_custom_command( + COMMAND "${TOP_SOURCE_DIR}/tests/examples/runner.sh" "${expected_output_path}" ${LUA_COV_RUNNER} ${template} ${test_path} ${IMAGE_PATH} ${IGNORE_ERRORS} + # COMMENT "Running ${rel_test_path} (via ${rel_template}, generating ${rel_output})" + DEPENDS ${template} ${test_path} + OUTPUT ${OUTPUT_IMAGE_PATH} + VERBATIM) + endif() set(EXAMPLE_DOC_GENERATED_FILES ${OUTPUT_IMAGE_PATH} ${EXAMPLE_DOC_GENERATED_FILES} PARENT_SCOPE) + elseif(tmp_content MATCHES "--DOC_GEN_OUTPUT") + add_custom_command( + COMMAND "${TOP_SOURCE_DIR}/tests/examples/runner.sh" "${expected_output_path}" ${LUA_COV_RUNNER} ${template} ${test_path} "" ${IGNORE_ERRORS} + # COMMENT "Running ${rel_test_path} (via ${rel_template}, generating ${rel_output})" + DEPENDS ${template} ${test_path} + OUTPUT ${expected_output_path} + VERBATIM) endif() # Export the outout to the parent scope. diff --git a/tests/examples/runner.sh b/tests/examples/runner.sh index 2c1e7022e..3084e934b 100755 --- a/tests/examples/runner.sh +++ b/tests/examples/runner.sh @@ -49,6 +49,7 @@ if ! cmp --silent "${file_stdout}" "${expected_output}" then echo "Expected text from ${expected_output}, but got:" diff -u "${expected_output}" "${file_stdout}" || true + cp "${file_stdout}" "${expected_output}" exit 1 fi diff --git a/tests/examples/uml/nav_tables/client.lua b/tests/examples/uml/nav_tables/client.lua new file mode 100644 index 000000000..e46a04d94 --- /dev/null +++ b/tests/examples/uml/nav_tables/client.lua @@ -0,0 +1,101 @@ +--DOC_GEN_OUTPUT --DOC_NO_USAGE --DOC_HIDE_ALL --DOC_ASTERISK --DOC_RAW_OUTPUT --DOC_GEN_IMAGE +local module = ... + +module.generate_nav_table { + class = "client", + content = { + { + association = "aggregation", + class = "tag", + to_property = "c.tags", + from_property = "t:clients()", + left = { + msg = "Is tagged on", + card = "1..N", + }, + right = { + msg = "Attached to", + card = "0..N", + }, + }, + { + association = "aggregation", + class = "screen", + to_property = "c.screen", + from_property = "s.clients", + left = { + msg = "Is on", + card = "1..1", + }, + right = { + msg = "Has", + card = "0..N", + }, + }, + { + association = "aggregation", + class = "screen", + from_property = "s.hidden_clients", + left = { + msg = "Is on", + card = "1..1", + }, + right = { + msg = "Has", + card = "0..N", + }, + }, + { + association = "aggregation", + class = "screen", + from_property = "s.tiled_clients", + left = { + msg = "Is on", + card = "1..1", + }, + right = { + msg = "Has", + card = "0..N", + }, + }, + { + association = "aggregation", + class = "awful.key", + to_property = "c:keys()", + left = { + msg = "Has", + card = "0..N", + }, + right = { + msg = "Attached to", + card = "0..N", + }, + }, + { + association = "aggregation", + class = "awful.button", + to_property = "c:buttons()", + left = { + msg = "Has", + card = "0..N", + }, + right = { + msg = "Attached to", + card = "0..N", + }, + }, + { + association = "aggregation", + class = "mouse", + from_property = "mouse.current_client", + left = { + msg = "Is below", + card = "0..1", + }, + right = { + msg = "Is over", + card = "0..1", + }, + }, + } +} diff --git a/tests/examples/uml/nav_tables/client.output.txt b/tests/examples/uml/nav_tables/client.output.txt new file mode 100644 index 000000000..65bc1681b --- /dev/null +++ b/tests/examples/uml/nav_tables/client.output.txt @@ -0,0 +1,77 @@ + + +Core components relationship +=== + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
Acquire other objects from a client
ClassProperty
tagc.tags
screenc.screen
awful.keyc:keys()
awful.buttonc:buttons()
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Acquire a client from other objects
ClassProperty
tagt:clients()
screens.clients
screens.hidden_clients
screens.tiled_clients
mousemouse.current_client
+ Legend: c: a client object, t: a tag object, + s: a screen object, k: an awful.key object, + b: a awful.button object, n: a naughty.notification object +
diff --git a/tests/examples/uml/nav_tables/screen.lua b/tests/examples/uml/nav_tables/screen.lua new file mode 100644 index 000000000..4e80253f6 --- /dev/null +++ b/tests/examples/uml/nav_tables/screen.lua @@ -0,0 +1,101 @@ +--DOC_GEN_OUTPUT --DOC_NO_USAGE --DOC_HIDE_ALL --DOC_ASTERISK --DOC_RAW_OUTPUT --DOC_GEN_IMAGE +local module = ... + +module.generate_nav_table { + class = "screen", + content = { + { + association = "aggregation", + class = "tag", + to_property = "s.tags", + from_property = "t.screen", + left = { + msg = "Has", + card = "0..N", + }, + right = { + msg = "Attached to", + card = "1..1", + }, + }, + { + association = "composition", + class = "tag", + to_property = "s.selected_tag", + left = { + msg = "Has", + card = "0..1", + }, + right = { + msg = "Is on", + card = "1..1", + }, + }, + { + association = "composition", + class = "tag", + to_property = "s.selected_tags", + left = { + msg = "Has", + card = "0..N", + }, + right = { + msg = "Is on", + card = "1..1", + }, + }, + { + association = "aggregation", + class = "client", + from_property = "c.screen", + to_property = "s.clients", + left = { + msg = "Has", + card = "0..N", + }, + right = { + msg = "Is on", + card = "1..1", + }, + }, + { + association = "aggregation", + class = "client", + to_property = "s.hidden_clients", + left = { + msg = "Has", + card = "1..1", + }, + right = { + msg = "Is on", + card = "1..1", + }, + }, + { + association = "aggregation", + class = "client", + to_property = "s.tiled_clients", + left = { + msg = "Has", + card = "0..N", + }, + right = { + msg = "Has", + card = "1..1", + }, + }, + { + association = "aggregation", + class = "naughty.notification", + from_property = "n.screen", + left = { + msg = "Displays", + card = "0..N", + }, + right = { + msg = "Is displayed on", + card = "1..N", + }, + }, + } +} diff --git a/tests/examples/uml/nav_tables/screen.output.txt b/tests/examples/uml/nav_tables/screen.output.txt new file mode 100644 index 000000000..d7b307854 --- /dev/null +++ b/tests/examples/uml/nav_tables/screen.output.txt @@ -0,0 +1,77 @@ + + +Core components relationship +=== + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Acquire other objects from a screen
ClassProperty
tags.tags
tags.selected_tag
tags.selected_tags
clients.clients
clients.hidden_clients
clients.tiled_clients
+ + + + + + + + + + + + + + + + + + + + + + +
Acquire a screen from other objects
ClassProperty
tagt.screen
clientc.screen
naughty.notificationn.screen
+ Legend: c: a client object, t: a tag object, + s: a screen object, k: an awful.key object, + b: a awful.button object, n: a naughty.notification object +
diff --git a/tests/examples/uml/nav_tables/tag.lua b/tests/examples/uml/nav_tables/tag.lua new file mode 100644 index 000000000..6637c6171 --- /dev/null +++ b/tests/examples/uml/nav_tables/tag.lua @@ -0,0 +1,62 @@ +--DOC_GEN_OUTPUT --DOC_NO_USAGE --DOC_HIDE_ALL --DOC_ASTERISK --DOC_RAW_OUTPUT --DOC_GEN_IMAGE +local module = ... + +module.generate_nav_table { + class = "tag", + content = { + { + association = "aggregation", + class = "client", + from_property = "c.tags", + to_property = "t:clients()", + right = { + msg = "Is tagged on", + card = "1..N", + }, + left = { + msg = "Has", + card = "0..N", + }, + }, + { + association = "composition", + class = "screen", + to_property = "t.screen", + from_property = "s.tags", + left = { + msg = "Is displayed on", + card = "1..1", + }, + right = { + msg = "Has", + card = "0..N", + }, + }, + { + association = "composition", + class = "screen", + from_property = "s.selected_tag", + left = { + msg = "Is on", + card = "1..1", + }, + right = { + msg = "Has", + card = "0..N", + }, + }, + { + association = "composition", + class = "screen", + from_property = "s.selected_tags", + left = { + msg = "Is on", + card = "1..1", + }, + right = { + msg = "Has", + card = "0..N", + }, + }, + } +} diff --git a/tests/examples/uml/nav_tables/tag.output.txt b/tests/examples/uml/nav_tables/tag.output.txt new file mode 100644 index 000000000..55b9ac223 --- /dev/null +++ b/tests/examples/uml/nav_tables/tag.output.txt @@ -0,0 +1,62 @@ + + +Core components relationship +=== + + + + + + + +
+ + + + + + + + + + + + + + + + + +
Acquire other objects from a tag
ClassProperty
clientt:clients()
screent.screen
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
Acquire a tag from other objects
ClassProperty
clientc.tags
screens.tags
screens.selected_tag
screens.selected_tags
+ Legend: c: a client object, t: a tag object, + s: a screen object, k: an awful.key object, + b: a awful.button object, n: a naughty.notification object +
diff --git a/tests/examples/uml/template.lua b/tests/examples/uml/template.lua new file mode 100644 index 000000000..1b24ede41 --- /dev/null +++ b/tests/examples/uml/template.lua @@ -0,0 +1,228 @@ +local file_path, image_path = ... +require("_common_template")(...) +local cairo = require("lgi").cairo +local shape = require("gears.shape") +local wibox = require("wibox") +local beautiful = require("beautiful") + +-- Make the path relative. +image_path = "../" .. image_path:match("/(images/[^/]+)$") + +-- This template generates an HTML table with how other classes are associated +-- with a given class. + +local function gen_class(name) + return wibox.widget { + { + { + { + valign = "center", + align = "center", + markup = ""..name.."", + widget = wibox.widget.textbox + }, + fg = "#ffffff", + bg = beautiful.bg_normal, + widget = wibox.container.background, + }, + nil, + nil, + widget = wibox.layout.align.vertical, + }, + shape = function(cr,w,h) + shape.partially_rounded_rect(cr,w,h, true,true,false,false,5) + end, + forced_width = 75, + border_width = 1, + border_strategy = "inner", + border_color = beautiful.border_color, + bg = "#00000000", + widget = wibox.container.background + } +end + +local function gen_arrow(association) + local w = wibox.widget.base.make_widget() + + function w:fit(_, width, _) + return width, 15 + end + + function w:draw(_, cr, width, height) + cr:set_line_width(1.5) + cr:move_to(0, height/2) + cr:line_to(width-(association == "association" and 0 or 40), height/2) + cr:stroke() + + if association ~= "association" then + cr:set_antialias(cairo.ANTIALIAS_SUBPIXEL) + cr:set_line_width(1) + cr:translate(0,2) + width, height = width-2, height-4 + cr:move_to(width-40, height/2) + cr:line_to(width-20, 0 ) + cr:line_to(width , height/2) + cr:line_to(width-20, height ) + cr:line_to(width-40, height/2) + cr:close_path() + + if association == "composition" then + cr:fill() + else + cr:stroke() + end + end + end + + w.forced_height = 15 + + return w +end + +local function arrow_widget(dir) + local w = wibox.widget.base.make_widget() + + function w:fit(_, width, _) + return width, 5 + end + + function w:draw(_, cr, width, height) + + cr:translate(10, 0) + width = width - 20 + + cr:set_source_rgba(0,0,0,0.2) + cr:set_line_width(1) + cr:move_to(0, height/2) + cr:line_to(width,height/2) + cr:stroke() + + if dir == "left" then + cr:move_to(height/2, 0) + cr:line_to(0, height/2) + cr:line_to(height/2, height) + cr:stroke() + else + cr:move_to(width-height/2, 0) + cr:line_to(width, height/2) + cr:line_to(width-height/2, height) + cr:stroke() + end + end + + return w +end + +local function gen_table_uml(entry, class1, class2, revert) + local left = revert and entry.right or entry.left + local right = revert and entry.left or entry.right + + return wibox.widget { + gen_class(class2), + { + { + { + text = " "..left.card, + widget = wibox.widget.textbox + }, + arrow_widget "left", + { + wrap = "char", + markup = left.msg.." .", + widget = wibox.widget.textbox + }, + spacing = 5, + layout = wibox.layout.align.horizontal + }, + gen_arrow(entry.composition), + { + { + wrap = "char", + markup = right.msg.." .", + widget = wibox.widget.textbox + }, + arrow_widget "right", + { + text = right.card.." ", + widget = wibox.widget.textbox + }, + spacing = 5, + layout = wibox.layout.align.horizontal + }, + layout = wibox.layout.fixed.vertical, + }, + gen_class(class1), + layout = wibox.layout.align.horizontal + } +end + +local map = { + to = function(o) return "Acquire other objects from a "..o end, + from = function(o) return "Acquire a "..o.." from other objects" end +} + +local function gen_table_header(title, o) + print([[ + + + + + + + ]]) + +end + +local function get_table_row(path, class, prop) + print([[ + + + + ]]) +end + +local function get_table_footer() + print '
]]..map[title](o)..[[
ClassProperty
]].. class ..[[]].. prop ..[[
' +end + +local module = {} + +local counter = 1 + +function module.generate_nav_table(t) + assert(t.content and t.class) + + print("\n\nCore components relationship\n===\n") + print '' + + -- Validate early to avoid debugging cryptic backtraces. + for _, tab in ipairs {"to", "from"} do + gen_table_header(tab, t.class) + for _, entry in ipairs(t.content) do + if entry[tab.."_property"] then + assert(entry.left and entry.right and entry.association) + assert(entry.class) + assert(entry.left.msg and entry.left.card) + assert(entry.right.msg and entry.right.card) + local path = image_path..counter..".svg" + local widget = gen_table_uml(entry, t.class, entry.class, false) + wibox.widget.draw_to_svg_file(widget, path, 320, 50) + get_table_row(path, entry.class, entry[tab.."_property"]) + counter = counter + 1 + end + end + get_table_footer() + end + print([[ + + +
+ Legend: c: a client object, t: a tag object, + s: a screen object, k: an awful.key object, + b: a awful.button object, n: a naughty.notification object +
]]) +end + +loadfile(file_path)(module) + +-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80