Added settings.lua

This commit is contained in:
Mutzi 2023-01-25 20:10:58 +01:00
parent 80cc950271
commit 5cf452e053
38 changed files with 3880 additions and 3450 deletions

View File

@ -11,10 +11,10 @@
--]]
local awful = require("awful")
local theme = require("beautiful")
local utils = require("menubar.utils")
local wibox = require("wibox")
local awful = require('awful')
local theme = require('beautiful')
local utils = require('menubar.utils')
local wibox = require('wibox')
local io = io
local ipairs = ipairs
@ -30,20 +30,20 @@ local desktop = {
-- Default desktop basic icons
baseicons = {
[1] = {
label = "This PC",
icon = "computer",
onclick = "computer://"
label = 'This PC',
icon = 'computer',
onclick = 'computer://',
},
[2] = {
label = "Home",
icon = "user-home",
onclick = os.getenv("HOME")
label = 'Home',
icon = 'user-home',
onclick = os.getenv('HOME'),
},
[3] = {
label = "Trash",
icon = "user-trash",
onclick = "trash://"
}
label = 'Trash',
icon = 'user-trash',
onclick = 'trash://',
},
},
-- Default parameters
iconsize = { width = 48, height = 48 },
@ -62,7 +62,9 @@ local function pipelines(...)
local f = assert(io.popen(...))
return function()
local data = f:read()
if data == nil then f:close() end
if data == nil then
f:close()
end
return data
end
end
@ -78,18 +80,23 @@ function desktop.add_single_icon(args, label, icon, onclick)
-- define icon dimensions and position
if not dcp[s] then
dcp[s] = { x = (screen[s].geometry.x + args.iconsize.width + args.margin.x), y = screen[s].geometry.y + 20 + args.margin.y }
dcp[s] = {
x = (screen[s].geometry.x + args.iconsize.width + args.margin.x),
y = screen[s].geometry.y + 20 + args.margin.y,
}
end
local tot_height = (icon and args.iconsize.height or 0) + (label and args.labelsize.height or 0)
if tot_height == 0 then return end
if tot_height == 0 then
return
end
if dcp[s].y + tot_height > screen[s].geometry.y + screen[s].geometry.height - 20 - args.margin.y then
dcp[s].x = dcp[s].x + args.labelsize.width + args.iconsize.width + args.margin.x
dcp[s].y = 20 + args.margin.y
end
local common = { screen = s, bg = "#00000000", visible = true, type = "desktop" }
local common = { screen = s, bg = '#00000000', visible = true, type = 'desktop' }
-- create icon container
if icon then
@ -98,11 +105,11 @@ function desktop.add_single_icon(args, label, icon, onclick)
common.x = dcp[s].x
common.y = dcp[s].y
icon = wibox.widget {
icon = wibox.widget({
image = icon,
resize = false,
widget = wibox.widget.imagebox
}
widget = wibox.widget.imagebox,
})
icon:buttons(awful.button({}, 1, nil, onclick))
@ -119,14 +126,14 @@ function desktop.add_single_icon(args, label, icon, onclick)
common.x = dcp[s].x - (args.labelsize.width / 2) + args.iconsize.width / 2
common.y = dcp[s].y
caption = wibox.widget {
caption = wibox.widget({
text = label,
align = "center",
align = 'center',
forced_width = common.width,
forced_height = common.height,
ellipsize = "middle",
widget = wibox.widget.textbox
}
ellipsize = 'middle',
widget = wibox.widget.textbox,
})
caption:buttons(awful.button({}, 1, onclick))
caption_container = wibox(common)
@ -156,15 +163,15 @@ end
function desktop.lookup_file_icon(filename)
-- load system MIME types
if #mime_types == 0 then
for line in io.lines("/etc/mime.types") do
if not line:find("^#") then
for line in io.lines('/etc/mime.types') do
if not line:find('^#') then
local parsed = {}
for w in line:gmatch("[^%s]+") do
for w in line:gmatch('[^%s]+') do
table.insert(parsed, w)
end
if #parsed > 1 then
for i = 2, #parsed do
mime_types[parsed[i]] = parsed[1]:gsub("/", "-")
mime_types[parsed[i]] = parsed[1]:gsub('/', '-')
end
end
end
@ -172,23 +179,27 @@ function desktop.lookup_file_icon(filename)
end
-- try to search a possible icon among standards
local extension = filename:match("%a+$")
local mime = mime_types[extension] or ""
local mime_family = mime:match("^%a+") or ""
local extension = filename:match('%a+$')
local mime = mime_types[extension] or ''
local mime_family = mime:match('^%a+') or ''
local possible_filenames = {
mime, "gnome-mime-" .. mime,
mime_family, "gnome-mime-" .. mime_family,
extension
mime,
'gnome-mime-' .. mime,
mime_family,
'gnome-mime-' .. mime_family,
extension,
}
for i, filename in ipairs(possible_filenames) do
local icon = utils.lookup_icon(filename)
if icon then return icon end
if icon then
return icon
end
end
-- if we don"t find ad icon, then pretend is a plain text file
return utils.lookup_icon("text-x-generic")
return utils.lookup_icon('text-x-generic')
end
-- Parse subdirectories and files list from input directory
@ -198,20 +209,20 @@ function desktop.parse_dirs_and_files(dir)
local files = {}
local paths = pipelines('find ' .. dir .. ' -maxdepth 1 -type d |sort|tail -n +1')
for path in paths do
if path:match("[^/]+$") then
if path:match('[^/]+$') then
local file = {}
file.filename = path:match("[^/]+$")
file.filename = path:match('[^/]+$')
file.path = path
file.show = true
file.icon = utils.lookup_icon("folder")
file.icon = utils.lookup_icon('folder')
table.insert(files, file)
end
end
local paths = pipelines('find ' .. dir .. ' -maxdepth 1 -type f')
for path in paths do
if not path:find("%.desktop$") then
if not path:find('%.desktop$') then
local file = {}
file.filename = path:match("[^/]+$")
file.filename = path:match('[^/]+$')
file.path = path
file.show = true
file.icon = desktop.lookup_file_icon(file.filename)
@ -227,7 +238,9 @@ function desktop.add_dirs_and_files_icons(args)
for _, file in ipairs(desktop.parse_dirs_and_files(args.dir)) do
if file.show then
local label = args.showlabels and file.filename or nil
local onclick = function () awful.spawn(string.format("%s '%s'", args.open_with, file.path)) end
local onclick = function()
awful.spawn(string.format("%s '%s'", args.open_with, file.path))
end
desktop.add_single_icon(args, label, file.icon, onclick)
end
end
@ -238,9 +251,9 @@ end
function desktop.add_icons(args)
args = args or {}
args.screen = args.screen or mouse.screen
args.dir = args.dir or os.getenv("HOME") .. "/Desktop"
args.dir = args.dir or os.getenv('HOME') .. '/Desktop'
args.showlabels = args.showlabel or true
args.open_with = args.open_with or "xdg_open"
args.open_with = args.open_with or 'xdg_open'
args.baseicons = args.baseicons or desktop.baseicons
args.iconsize = args.iconsize or desktop.iconsize
args.labelsize = args.labelsize or desktop.labelsize
@ -249,7 +262,7 @@ function desktop.add_icons(args)
-- trying to fallback on Adwaita if theme.icon_theme is not defined
-- if Adwaita is missing too, no icons will be shown
if not theme.icon_theme then
theme.icon_theme = args.icon_theme or "Adwaita"
theme.icon_theme = args.icon_theme or 'Adwaita'
end
desktop.add_base_icons(args)

View File

@ -10,6 +10,6 @@
--]]
return {
desktop = require("freedesktop.desktop"),
menu = require("freedesktop.menu")
desktop = require('freedesktop.desktop'),
menu = require('freedesktop.menu'),
}

View File

@ -1,4 +1,3 @@
--[[
Awesome-Freedesktop
@ -12,15 +11,15 @@
--]]
local Gio = require("lgi").Gio
local awful_menu = require("awful.menu")
local menu_gen = require("menubar.menu_gen")
local menu_utils = require("menubar.utils")
local Gio = require('lgi').Gio
local awful_menu = require('awful.menu')
local menu_gen = require('menubar.menu_gen')
local menu_utils = require('menubar.utils')
local io, pairs, string, table, os = io, pairs, string, table, os
-- Expecting a wm_name of awesome omits too many applications and tools
menu_utils.wm_name = ""
menu_utils.wm_name = ''
-- Menu
-- freedesktop.menu
@ -30,7 +29,7 @@ local menu = {}
-- @tparam string path The directory path
-- @treturn boolean True if path exists and is a directory
function menu.is_dir(path)
return Gio.File.new_for_path(path):query_file_type({}) == "DIRECTORY"
return Gio.File.new_for_path(path):query_file_type({}) == 'DIRECTORY'
end
-- Remove non existent paths in order to avoid issues
@ -93,14 +92,18 @@ function menu.build(args)
table.remove(result, i)
else
--Sort entries alphabetically (by name)
table.sort(v[2], function (a, b) return string.byte(a[1]) < string.byte(b[1]) end)
table.sort(v[2], function(a, b)
return string.byte(a[1]) < string.byte(b[1])
end)
-- Replace category name with nice name
v[1] = menu_gen.all_categories[v[1]].name
end
end
-- Sort categories alphabetically also
table.sort(result, function(a, b) return string.byte(a[1]) < string.byte(b[1]) end)
table.sort(result, function(a, b)
return string.byte(a[1]) < string.byte(b[1])
end)
-- Add menu item to hold the generated menu
if sub_menu then
@ -108,8 +111,12 @@ function menu.build(args)
end
-- Add items to menu
for _, v in pairs(result) do _menu:add(v) end
for _, v in pairs(after) do _menu:add(v) end
for _, v in pairs(result) do
_menu:add(v)
end
for _, v in pairs(after) do
_menu:add(v)
end
end)
-- Hold the menu in the module

View File

@ -5,11 +5,10 @@
--]]
local spawn = require("awful.spawn")
local timer = require("gears.timer")
local debug = require("debug")
local io = { lines = io.lines,
open = io.open }
local spawn = require('awful.spawn')
local timer = require('gears.timer')
local debug = require('debug')
local io = { lines = io.lines, open = io.open }
local pairs = pairs
local rawget = rawget
local tsort = table.sort
@ -19,7 +18,7 @@ local unpack = unpack or table.unpack -- lua 5.1 retro-compatibility
-- lain.helpers
local helpers = {}
helpers.lain_dir = debug.getinfo(1, 'S').source:match[[^@(.*/).*$]]
helpers.lain_dir = debug.getinfo(1, 'S').source:match([[^@(.*/).*$]])
helpers.icons_dir = helpers.lain_dir .. 'icons/'
helpers.scripts_dir = helpers.lain_dir .. 'scripts/'
@ -35,8 +34,10 @@ end
-- check if the file exists and is readable
function helpers.file_exists(path)
local file = io.open(path, "rb")
if file then file:close() end
local file = io.open(path, 'rb')
if file then
file:close()
end
return file ~= nil
end
@ -62,9 +63,9 @@ end
-- get first line of a file
function helpers.first_line(path)
local file, first = io.open(path, "rb"), nil
local file, first = io.open(path, 'rb'), nil
if file then
first = file:read("*l")
first = file:read('*l')
file:close()
end
return first
@ -73,7 +74,9 @@ end
-- get first non empty line from a file
function helpers.first_nonempty_line(path)
for line in io.lines(path) do
if #line then return line end
if #line then
return line
end
end
return nil
end
@ -85,15 +88,17 @@ end
helpers.timer_table = {}
function helpers.newtimer(name, timeout, fun, nostart, stoppable)
if not name or #name == 0 then return end
if not name or #name == 0 then
return
end
name = (stoppable and name) or timeout
if not helpers.timer_table[name] then
helpers.timer_table[name] = timer({ timeout = timeout })
helpers.timer_table[name]:start()
end
helpers.timer_table[name]:connect_signal("timeout", fun)
helpers.timer_table[name]:connect_signal('timeout', fun)
if not nostart then
helpers.timer_table[name]:emit_signal("timeout")
helpers.timer_table[name]:emit_signal('timeout')
end
return stoppable and helpers.timer_table[name]
end
@ -107,16 +112,14 @@ end
-- @param callback function to execute on cmd output
-- @return cmd PID
function helpers.async(cmd, callback)
return spawn.easy_async(cmd,
function (stdout, _, _, exit_code)
return spawn.easy_async(cmd, function(stdout, _, _, exit_code)
callback(stdout, exit_code)
end)
end
-- like above, but call spawn.easy_async with a shell
function helpers.async_with_shell(cmd, callback)
return spawn.easy_async_with_shell(cmd,
function (stdout, _, _, exit_code)
return spawn.easy_async_with_shell(cmd, function(stdout, _, _, exit_code)
callback(stdout, exit_code)
end)
end
@ -162,7 +165,9 @@ end
function helpers.spairs(t)
-- collect the keys
local keys = {}
for k in pairs(t) do keys[#keys+1] = k end
for k in pairs(t) do
keys[#keys + 1] = k
end
tsort(keys)
@ -188,7 +193,9 @@ end
-- create the powerset of a given set
function helpers.powerset(s)
if not s then return {} end
if not s then
return {}
end
local t = { {} }
for i = 1, #s do
for j = 1, #t do

View File

@ -9,7 +9,7 @@
--]]
return {
layout = require("lain.layout"),
util = require("lain.util"),
widget = require("lain.widget")
layout = require('lain.layout'),
util = require('lain.util'),
widget = require('lain.widget'),
}

View File

@ -11,19 +11,19 @@ local floor = math.floor
local screen = screen
local cascade = {
name = "cascade",
name = 'cascade',
nmaster = 0,
offset_x = 32,
offset_y = 8,
tile = {
name = "cascadetile",
name = 'cascadetile',
nmaster = 0,
ncol = 0,
mwfact = 0,
offset_x = 5,
offset_y = 32,
extra_padding = 0
}
extra_padding = 0,
},
}
local function do_cascade(p, tiling)
@ -31,7 +31,9 @@ local function do_cascade(p, tiling)
local wa = p.workarea
local cls = p.clients
if #cls == 0 then return end
if #cls == 0 then
return
end
if not tiling then
-- Cascade windows.
@ -62,8 +64,12 @@ local function do_cascade(p, tiling)
g.width = wa.width - current_offset_x
g.height = wa.height - current_offset_y
if g.width < 1 then g.width = 1 end
if g.height < 1 then g.height = 1 end
if g.width < 1 then
g.width = 1
end
if g.height < 1 then
g.height = 1
end
p.geometries[c] = g
end
@ -109,7 +115,9 @@ local function do_cascade(p, tiling)
local current_offset_x = cascade.tile.offset_x * (how_many - 1)
local current_offset_y = cascade.tile.offset_y * (how_many - 1)
if #cls <= 0 then return end
if #cls <= 0 then
return
end
-- Main column, fixed width and height.
local c = cls[1]
@ -136,13 +144,19 @@ local function do_cascade(p, tiling)
g.x = wa.x
g.y = wa.y
if g.width < 1 then g.width = 1 end
if g.height < 1 then g.height = 1 end
if g.width < 1 then
g.width = 1
end
if g.height < 1 then
g.height = 1
end
p.geometries[c] = g
-- Remaining clients stacked in slave column, new ones on top.
if #cls <= 1 then return end
if #cls <= 1 then
return
end
for i = 2, #cls do
c = cls[i]
g = {}
@ -153,8 +167,12 @@ local function do_cascade(p, tiling)
g.x = wa.x + mainwid + (how_many - (i - 1)) * cascade.tile.offset_x
g.y = wa.y + (i - 2) * cascade.tile.offset_y
if g.width < 1 then g.width = 1 end
if g.height < 1 then g.height = 1 end
if g.width < 1 then
g.width = 1
end
if g.height < 1 then
g.height = 1
end
p.geometries[c] = g
end

View File

@ -17,8 +17,8 @@ local mousegrabber = mousegrabber
local screen = screen
local centerwork = {
name = "centerwork",
horizontal = { name = "centerworkh" }
name = 'centerwork',
horizontal = { name = 'centerworkh' },
}
local function arrange(p, layout)
@ -26,7 +26,9 @@ local function arrange(p, layout)
local wa = p.workarea
local cls = p.clients
if #cls == 0 then return end
if #cls == 0 then
return
end
local g = {}
@ -45,9 +47,13 @@ local function arrange(p, layout)
local slaveFirstDim, slaveSecondDim = 0, 0
if layout.name == "centerwork" then -- vertical
if nbrFirstSlaves > 0 then slaveFirstDim = floor(wa.height / nbrFirstSlaves) end
if nbrSecondSlaves > 0 then slaveSecondDim = floor(wa.height / nbrSecondSlaves) end
if layout.name == 'centerwork' then -- vertical
if nbrFirstSlaves > 0 then
slaveFirstDim = floor(wa.height / nbrFirstSlaves)
end
if nbrSecondSlaves > 0 then
slaveSecondDim = floor(wa.height / nbrSecondSlaves)
end
g.height = wa.height
g.width = mainwid
@ -55,8 +61,12 @@ local function arrange(p, layout)
g.x = wa.x + slaveLwid
g.y = wa.y
else -- horizontal
if nbrFirstSlaves > 0 then slaveFirstDim = floor(wa.width / nbrFirstSlaves) end
if nbrSecondSlaves > 0 then slaveSecondDim = floor(wa.width / nbrSecondSlaves) end
if nbrFirstSlaves > 0 then
slaveFirstDim = floor(wa.width / nbrFirstSlaves)
end
if nbrSecondSlaves > 0 then
slaveSecondDim = floor(wa.width / nbrSecondSlaves)
end
g.height = mainhei
g.width = wa.width
@ -71,14 +81,16 @@ local function arrange(p, layout)
p.geometries[cls[1]] = g
-- Auxiliary clients
if #cls <= 1 then return end
if #cls <= 1 then
return
end
for i = 2, #cls do
g = {}
local idxChecker, dimToAssign
local rowIndex = floor(i / 2)
if layout.name == "centerwork" then
if layout.name == 'centerwork' then
if i % 2 == 0 then -- left slave
g.x = wa.x
g.y = wa.y + (rowIndex - 1) * slaveFirstDim
@ -134,22 +146,22 @@ local function mouse_resize_handler(c, _, _, _, orientation)
local mwfact = c.screen.selected_tag.master_width_factor
local g = c:geometry()
local offset = 0
local cursor = "cross"
local cursor = 'cross'
local corner_coords
if orientation == 'vertical' then
if g.height + 15 >= wa.height then
offset = g.height * .5
cursor = "sb_h_double_arrow"
offset = g.height * 0.5
cursor = 'sb_h_double_arrow'
elseif g.y + g.height + 15 <= wa.y + wa.height then
offset = g.height
end
corner_coords = { x = wa.x + wa.width * (1 - mwfact) / 2, y = g.y + offset }
else
if g.width + 15 >= wa.width then
offset = g.width * .5
cursor = "sb_v_double_arrow"
offset = g.width * 0.5
cursor = 'sb_v_double_arrow'
elseif g.x + g.width + 15 <= wa.x + wa.width then
offset = g.width
end
@ -161,7 +173,9 @@ local function mouse_resize_handler(c, _, _, _, orientation)
local prev_coords = {}
mousegrabber.run(function(m)
if not c.valid then return false end
if not c.valid then
return false
end
for _, v in ipairs(m.buttons) do
if v then
prev_coords = { x = m.x, y = m.y }
@ -195,13 +209,12 @@ function centerwork.horizontal.mouse_resize_handler(c, corner, x, y)
return mouse_resize_handler(c, corner, x, y, 'horizontal')
end
--[[
Make focus.byidx and swap.byidx behave more consistently with other layouts.
--]]
local awful = require("awful")
local gears = require("gears")
local awful = require('awful')
local gears = require('gears')
local client = client
local function compare_position(a, b)
@ -217,7 +230,9 @@ local function clients_by_position()
if this then
local sorted = {}
for _, c in ipairs(client.focus.first_tag:clients()) do
if not c.minimized then sorted[#sorted+1] = c end
if not c.minimized then
sorted[#sorted + 1] = c
end
end
table.sort(sorted, compare_position)
@ -236,12 +251,11 @@ local function clients_by_position()
end
local function in_centerwork()
return client.focus and client.focus.first_tag.layout.name == "centerwork"
return client.focus and client.focus.first_tag.layout.name == 'centerwork'
end
centerwork.focus = {}
--[[
Drop in replacements for awful.client.focus.byidx and awful.client.swap.byidx
that behaves consistently with other layouts.

View File

@ -11,9 +11,9 @@
--]]
local wrequire = require("lain.helpers").wrequire
local wrequire = require('lain.helpers').wrequire
local setmetatable = setmetatable
local layout = { _NAME = "lain.layout" }
local layout = { _NAME = 'lain.layout' }
return setmetatable(layout, { __index = wrequire })

View File

@ -12,25 +12,31 @@ local math = math
local screen = screen
local tonumber = tonumber
local termfair = { name = "termfair" }
termfair.center = { name = "centerfair" }
termfair.stable = { name = "stablefair" }
local termfair = { name = 'termfair' }
termfair.center = { name = 'centerfair' }
termfair.stable = { name = 'stablefair' }
local function do_fair(p, orientation)
local t = p.tag or screen[p.screen].selected_tag
local wa = p.workarea
local cls = p.clients
if #cls == 0 then return end
if #cls == 0 then
return
end
-- How many vertical columns? Read from nmaster on the tag.
local num_x = tonumber(termfair.nmaster) or t.master_count
local ncol = tonumber(termfair.ncol) or t.column_count
if num_x <= 2 then num_x = 2 end
if ncol <= 1 then ncol = 1 end
if num_x <= 2 then
num_x = 2
end
if ncol <= 1 then
ncol = 1
end
local width = math.floor(wa.width / num_x)
if orientation == "west" then
if orientation == 'west' then
-- Layout with fixed number of vertical columns (read from nmaster).
-- New windows align from left to right. When a row is full, a new
-- one above it is created. Like this:
@ -87,8 +93,12 @@ local function do_fair(p, orientation)
g.x = wa.x + this_x * width
g.y = wa.y + this_y * height
if g.width < 1 then g.width = 1 end
if g.height < 1 then g.height = 1 end
if g.width < 1 then
g.width = 1
end
if g.height < 1 then
g.height = 1
end
p.geometries[c] = g
@ -107,7 +117,7 @@ local function do_fair(p, orientation)
end
end
end
elseif orientation == "stable" then
elseif orientation == 'stable' then
-- Layout with fixed number of vertical columns (read from nmaster).
-- New windows align from left to right. When a row is full, a new
-- one below it is created. Like this:
@ -152,12 +162,16 @@ local function do_fair(p, orientation)
g.x = wa.x + this_x * width
g.y = wa.y + this_y * height
if g.width < 1 then g.width = 1 end
if g.height < 1 then g.height = 1 end
if g.width < 1 then
g.width = 1
end
if g.height < 1 then
g.height = 1
end
p.geometries[c] = g
end
elseif orientation == "center" then
elseif orientation == 'center' then
-- Layout with fixed number of vertical columns (read from nmaster).
-- Cols are centerded until there is nmaster columns, then windows
-- are stacked in the slave columns, with at most ncol clients per
@ -185,8 +199,12 @@ local function do_fair(p, orientation)
local g = { y = wa.y }
g.width = width
g.height = wa.height
if g.width < 1 then g.width = 1 end
if g.height < 1 then g.height = 1 end
if g.width < 1 then
g.width = 1
end
if g.height < 1 then
g.height = 1
end
g.x = offset_x + (i - 1) * width
p.geometries[cls[i]] = g
end
@ -196,8 +214,12 @@ local function do_fair(p, orientation)
local g = {}
g.width = wa.width - (num_x - 1) * width
g.height = wa.height
if g.width < 1 then g.width = 1 end
if g.height < 1 then g.height = 1 end
if g.width < 1 then
g.width = 1
end
if g.height < 1 then
g.height = 1
end
g.x = wa.x
g.y = wa.y
p.geometries[cls[1]] = g
@ -246,8 +268,12 @@ local function do_fair(p, orientation)
g.y = wy
g.height = height
g.width = width
if g.width < 1 then g.width = 1 end
if g.height < 1 then g.height = 1 end
if g.width < 1 then
g.width = 1
end
if g.height < 1 then
g.height = 1
end
p.geometries[cls[nclient]] = g
nclient = nclient + 1
wy = wy + height
@ -257,8 +283,12 @@ local function do_fair(p, orientation)
g.y = wy
g.height = wa.height - (num_y[i] - 1) * height
g.width = width
if g.width < 1 then g.width = 1 end
if g.height < 1 then g.height = 1 end
if g.width < 1 then
g.width = 1
end
if g.height < 1 then
g.height = 1
end
p.geometries[cls[nclient]] = g
nclient = nclient + 1
wx = wx + width
@ -268,15 +298,15 @@ local function do_fair(p, orientation)
end
function termfair.center.arrange(p)
return do_fair(p, "center")
return do_fair(p, 'center')
end
function termfair.stable.arrange(p)
return do_fair(p, "stable")
return do_fair(p, 'stable')
end
function termfair.arrange(p)
return do_fair(p, "west")
return do_fair(p, 'west')
end
return termfair

View File

@ -47,12 +47,11 @@ local pairs, type, tostring, tonumber, getmetatable, setmetatable =
local error, require, pcall, select = error, require, pcall, select
local floor, huge = math.floor, math.huge
local strrep, gsub, strsub, strbyte, strchar, strfind, strlen, strformat =
string.rep, string.gsub, string.sub, string.byte, string.char,
string.find, string.len, string.format
string.rep, string.gsub, string.sub, string.byte, string.char, string.find, string.len, string.format
local strmatch = string.match
local concat = table.concat
local json = { version = "dkjson 2.6" }
local json = { version = 'dkjson 2.6' }
local jsonlpeg = {}
@ -69,12 +68,16 @@ _ENV = nil -- blocking globals in Lua 5.2 and later
pcall(function()
-- Enable access to blocked metatables.
-- Don't worry, this module doesn't change anything in them.
local debmeta = require "debug".getmetatable
if debmeta then getmetatable = debmeta end
local debmeta = require('debug').getmetatable
if debmeta then
getmetatable = debmeta
end
end)
json.null = setmetatable({}, {
__tojson = function () return "null" end
__tojson = function()
return 'null'
end,
})
local function isarray(tbl)
@ -102,8 +105,13 @@ local function isarray (tbl)
end
local escapecodes = {
["\""] = "\\\"", ["\\"] = "\\\\", ["\b"] = "\\b", ["\f"] = "\\f",
["\n"] = "\\n", ["\r"] = "\\r", ["\t"] = "\\t"
['"'] = '\\"',
['\\'] = '\\\\',
['\b'] = '\\b',
['\f'] = '\\f',
['\n'] = '\\n',
['\r'] = '\\r',
['\t'] = '\\t',
}
local function escapeutf8(uchar)
@ -122,17 +130,17 @@ local function escapeutf8 (uchar)
elseif 0xf0 <= a and a <= 0xf7 and b >= 0x80 and c >= 0x80 and d >= 0x80 then
value = (((a - 0xf0) * 0x40 + b - 0x80) * 0x40 + c - 0x80) * 0x40 + d - 0x80
else
return ""
return ''
end
if value <= 0xffff then
return strformat ("\\u%.4x", value)
return strformat('\\u%.4x', value)
elseif value <= 0x10ffff then
-- encode as UTF-16 surrogate pair
value = value - 0x10000
local highsur, lowsur = 0xD800 + floor(value / 0x400), 0xDC00 + (value % 0x400)
return strformat ("\\u%.4x\\u%.4x", highsur, lowsur)
return strformat('\\u%.4x\\u%.4x', highsur, lowsur)
else
return ""
return ''
end
end
@ -149,18 +157,18 @@ end
local function quotestring(value)
-- based on the regexp "escapable" in https://github.com/douglascrockford/JSON-js
value = fsub (value, "[%z\1-\31\"\\\127]", escapeutf8)
if strfind (value, "[\194\216\220\225\226\239]") then
value = fsub (value, "\194[\128-\159\173]", escapeutf8)
value = fsub (value, "\216[\128-\132]", escapeutf8)
value = fsub (value, "\220\143", escapeutf8)
value = fsub (value, "\225\158[\180\181]", escapeutf8)
value = fsub (value, "\226\128[\140-\143\168-\175]", escapeutf8)
value = fsub (value, "\226\129[\160-\175]", escapeutf8)
value = fsub (value, "\239\187\191", escapeutf8)
value = fsub (value, "\239\191[\176-\191]", escapeutf8)
value = fsub(value, '[%z\1-\31"\\\127]', escapeutf8)
if strfind(value, '[\194\216\220\225\226\239]') then
value = fsub(value, '\194[\128-\159\173]', escapeutf8)
value = fsub(value, '\216[\128-\132]', escapeutf8)
value = fsub(value, '\220\143', escapeutf8)
value = fsub(value, '\225\158[\180\181]', escapeutf8)
value = fsub(value, '\226\128[\140-\143\168-\175]', escapeutf8)
value = fsub(value, '\226\129[\160-\175]', escapeutf8)
value = fsub(value, '\239\187\191', escapeutf8)
value = fsub(value, '\239\191[\176-\191]', escapeutf8)
end
return "\"" .. value .. "\""
return '"' .. value .. '"'
end
json.quotestring = quotestring
@ -177,37 +185,36 @@ end
local decpoint, numfilter
local function updatedecpoint()
decpoint = strmatch(tostring(0.5), "([^05+])")
decpoint = strmatch(tostring(0.5), '([^05+])')
-- build a filter that can be used to remove group separators
numfilter = "[^0-9%-%+eE" .. gsub(decpoint, "[%^%$%(%)%%%.%[%]%*%+%-%?]", "%%%0") .. "]+"
numfilter = '[^0-9%-%+eE' .. gsub(decpoint, '[%^%$%(%)%%%.%[%]%*%+%-%?]', '%%%0') .. ']+'
end
updatedecpoint()
local function num2str(num)
return replace(fsub(tostring(num), numfilter, ""), decpoint, ".")
return replace(fsub(tostring(num), numfilter, ''), decpoint, '.')
end
local function str2num(str)
local num = tonumber(replace(str, ".", decpoint))
local num = tonumber(replace(str, '.', decpoint))
if not num then
updatedecpoint()
num = tonumber(replace(str, ".", decpoint))
num = tonumber(replace(str, '.', decpoint))
end
return num
end
local function addnewline2(level, buffer, buflen)
buffer[buflen+1] = "\n"
buffer[buflen+2] = strrep (" ", level)
buffer[buflen + 1] = '\n'
buffer[buflen + 2] = strrep(' ', level)
buflen = buflen + 2
return buflen
end
function json.addnewline(state)
if state.indent then
state.bufferlen = addnewline2 (state.level or 0,
state.buffer, state.bufferlen or #(state.buffer))
state.bufferlen = addnewline2(state.level or 0, state.buffer, state.bufferlen or #state.buffer)
end
end
@ -220,13 +227,13 @@ local function addpair (key, value, prev, indent, level, buffer, buflen, tables,
end
if prev then
buflen = buflen + 1
buffer[buflen] = ","
buffer[buflen] = ','
end
if indent then
buflen = addnewline2(level, buffer, buflen)
end
buffer[buflen + 1] = quotestring(key)
buffer[buflen+2] = ":"
buffer[buflen + 2] = ':'
return encode2(value, indent, level, buffer, buflen + 2, tables, globalorder, state)
end
@ -247,13 +254,15 @@ local function exception(reason, value, state, buffer, buflen, defaultmessage)
else
state.bufferlen = buflen
local ret, msg = handler(reason, value, state, defaultmessage)
if not ret then return nil, msg or defaultmessage end
if not ret then
return nil, msg or defaultmessage
end
return appendcustom(ret, buffer, state)
end
end
function json.encodeexception(_reason, _value, _state, defaultmessage)
return quotestring("<" .. defaultmessage .. ">")
return quotestring('<' .. defaultmessage .. '>')
end
encode2 = function(value, indent, level, buffer, buflen, tables, globalorder, state)
@ -268,17 +277,19 @@ encode2 = function (value, indent, level, buffer, buflen, tables, globalorder, s
tables[value] = true
state.bufferlen = buflen
local ret, msg = valtojson(value, state)
if not ret then return exception('custom encoder failed', value, state, buffer, buflen, msg) end
if not ret then
return exception('custom encoder failed', value, state, buffer, buflen, msg)
end
tables[value] = nil
buflen = appendcustom(ret, buffer, state)
elseif value == nil then
buflen = buflen + 1
buffer[buflen] = "null"
buffer[buflen] = 'null'
elseif valtype == 'number' then
local s
if value ~= value or value >= huge or -value >= huge then
-- This is the behaviour of the original JSON implementation.
s = "null"
s = 'null'
else
s = num2str(value)
end
@ -286,7 +297,7 @@ encode2 = function (value, indent, level, buffer, buflen, tables, globalorder, s
buffer[buflen] = s
elseif valtype == 'boolean' then
buflen = buflen + 1
buffer[buflen] = value and "true" or "false"
buffer[buflen] = value and 'true' or 'false'
elseif valtype == 'string' then
buflen = buflen + 1
buffer[buflen] = quotestring(value)
@ -303,21 +314,23 @@ encode2 = function (value, indent, level, buffer, buflen, tables, globalorder, s
local msg
if isa then -- JSON array
buflen = buflen + 1
buffer[buflen] = "["
buffer[buflen] = '['
for i = 1, n do
buflen, msg = encode2(value[i], indent, level, buffer, buflen, tables, globalorder, state)
if not buflen then return nil, msg end
if not buflen then
return nil, msg
end
if i < n then
buflen = buflen + 1
buffer[buflen] = ","
buffer[buflen] = ','
end
end
buflen = buflen + 1
buffer[buflen] = "]"
buffer[buflen] = ']'
else -- JSON object
local prev = false
buflen = buflen + 1
buffer[buflen] = "{"
buffer[buflen] = '{'
local order = valmeta and valmeta.__jsonorder or globalorder
if order then
local used = {}
@ -334,14 +347,18 @@ encode2 = function (value, indent, level, buffer, buflen, tables, globalorder, s
for k, v in pairs(value) do
if not used[k] then
buflen, msg = addpair(k, v, prev, indent, level, buffer, buflen, tables, globalorder, state)
if not buflen then return nil, msg end
if not buflen then
return nil, msg
end
prev = true -- add a seperator before the next element
end
end
else -- unordered
for k, v in pairs(value) do
buflen, msg = addpair(k, v, prev, indent, level, buffer, buflen, tables, globalorder, state)
if not buflen then return nil, msg end
if not buflen then
return nil, msg
end
prev = true -- add a seperator before the next element
end
end
@ -349,12 +366,18 @@ encode2 = function (value, indent, level, buffer, buflen, tables, globalorder, s
buflen = addnewline2(level - 1, buffer, buflen)
end
buflen = buflen + 1
buffer[buflen] = "}"
buffer[buflen] = '}'
end
tables[value] = nil
else
return exception ('unsupported type', value, state, buffer, buflen,
"type '" .. valtype .. "' is not supported by JSON.")
return exception(
'unsupported type',
value,
state,
buffer,
buflen,
"type '" .. valtype .. "' is not supported by JSON."
)
end
return buflen
end
@ -365,8 +388,16 @@ function json.encode (value, state)
local buffer = oldbuffer or {}
state.buffer = buffer
updatedecpoint()
local ret, msg = encode2 (value, state.indent, state.level or 0,
buffer, state.bufferlen or 0, state.tables or {}, state.keyorder, state)
local ret, msg = encode2(
value,
state.indent,
state.level or 0,
buffer,
state.bufferlen or 0,
state.tables or {},
state.keyorder,
state
)
if not ret then
error(msg, 2)
elseif oldbuffer == buffer then
@ -382,7 +413,7 @@ end
local function loc(str, where)
local line, pos, linepos = 1, 1, 0
while true do
pos = strfind (str, "\n", pos, true)
pos = strfind(str, '\n', pos, true)
if pos and pos < where then
line = line + 1
linepos = pos
@ -391,27 +422,33 @@ local function loc (str, where)
break
end
end
return "line " .. line .. ", column " .. (where - linepos)
return 'line ' .. line .. ', column ' .. (where - linepos)
end
local function unterminated(str, what, where)
return nil, strlen (str) + 1, "unterminated " .. what .. " at " .. loc (str, where)
return nil, strlen(str) + 1, 'unterminated ' .. what .. ' at ' .. loc(str, where)
end
local function scanwhite(str, pos)
while true do
pos = strfind (str, "%S", pos)
if not pos then return nil end
pos = strfind(str, '%S', pos)
if not pos then
return nil
end
local sub2 = strsub(str, pos, pos + 1)
if sub2 == "\239\187" and strsub (str, pos + 2, pos + 2) == "\191" then
if sub2 == '\239\187' and strsub(str, pos + 2, pos + 2) == '\191' then
-- UTF-8 Byte Order Mark
pos = pos + 3
elseif sub2 == "//" then
pos = strfind (str, "[\n\r]", pos + 2)
if not pos then return nil end
elseif sub2 == "/*" then
pos = strfind (str, "*/", pos + 2)
if not pos then return nil end
elseif sub2 == '//' then
pos = strfind(str, '[\n\r]', pos + 2)
if not pos then
return nil
end
elseif sub2 == '/*' then
pos = strfind(str, '*/', pos + 2)
if not pos then
return nil
end
pos = pos + 2
else
return pos
@ -420,8 +457,14 @@ local function scanwhite (str, pos)
end
local escapechars = {
["\""] = "\"", ["\\"] = "\\", ["/"] = "/", ["b"] = "\b", ["f"] = "\f",
["n"] = "\n", ["r"] = "\r", ["t"] = "\t"
['"'] = '"',
['\\'] = '\\',
['/'] = '/',
['b'] = '\b',
['f'] = '\f',
['n'] = '\n',
['r'] = '\r',
['t'] = '\t',
}
local function unichar(value)
@ -430,17 +473,16 @@ local function unichar (value)
elseif value <= 0x007f then
return strchar(value)
elseif value <= 0x07ff then
return strchar (0xc0 + floor(value/0x40),
0x80 + (floor(value) % 0x40))
return strchar(0xc0 + floor(value / 0x40), 0x80 + (floor(value) % 0x40))
elseif value <= 0xffff then
return strchar (0xe0 + floor(value/0x1000),
0x80 + (floor(value/0x40) % 0x40),
0x80 + (floor(value) % 0x40))
return strchar(0xe0 + floor(value / 0x1000), 0x80 + (floor(value / 0x40) % 0x40), 0x80 + (floor(value) % 0x40))
elseif value <= 0x10ffff then
return strchar (0xf0 + floor(value/0x40000),
return strchar(
0xf0 + floor(value / 0x40000),
0x80 + (floor(value / 0x1000) % 0x40),
0x80 + (floor(value / 0x40) % 0x40),
0x80 + (floor(value) % 0x40))
0x80 + (floor(value) % 0x40)
)
else
return nil
end
@ -450,28 +492,28 @@ local function scanstring (str, pos)
local lastpos = pos + 1
local buffer, n = {}, 0
while true do
local nextpos = strfind (str, "[\"\\]", lastpos)
local nextpos = strfind(str, '["\\]', lastpos)
if not nextpos then
return unterminated (str, "string", pos)
return unterminated(str, 'string', pos)
end
if nextpos > lastpos then
n = n + 1
buffer[n] = strsub(str, lastpos, nextpos - 1)
end
if strsub (str, nextpos, nextpos) == "\"" then
if strsub(str, nextpos, nextpos) == '"' then
lastpos = nextpos + 1
break
else
local escchar = strsub(str, nextpos + 1, nextpos + 1)
local value
if escchar == "u" then
if escchar == 'u' then
value = tonumber(strsub(str, nextpos + 2, nextpos + 5), 16)
if value then
local value2
if 0xD800 <= value and value <= 0xDBff then
-- we have the high surrogate of UTF-16. Check if there is a
-- low surrogate escaped nearby to combine them.
if strsub (str, nextpos + 6, nextpos + 7) == "\\u" then
if strsub(str, nextpos + 6, nextpos + 7) == '\\u' then
value2 = tonumber(strsub(str, nextpos + 8, nextpos + 11), 16)
if value2 and 0xDC00 <= value2 and value2 <= 0xDFFF then
value = (value - 0xD800) * 0x400 + (value2 - 0xDC00) + 0x10000
@ -503,7 +545,7 @@ local function scanstring (str, pos)
elseif n > 1 then
return concat(buffer), lastpos
else
return "", lastpos
return '', lastpos
end
end
@ -519,35 +561,47 @@ local function scantable (what, closechar, str, startpos, nullval, objectmeta, a
end
while true do
pos = scanwhite(str, pos)
if not pos then return unterminated (str, what, startpos) end
if not pos then
return unterminated(str, what, startpos)
end
local char = strsub(str, pos, pos)
if char == closechar then
return tbl, pos + 1
end
local val1, err
val1, pos, err = scanvalue(str, pos, nullval, objectmeta, arraymeta)
if err then return nil, pos, err end
if err then
return nil, pos, err
end
pos = scanwhite(str, pos)
if not pos then return unterminated (str, what, startpos) end
if not pos then
return unterminated(str, what, startpos)
end
char = strsub(str, pos, pos)
if char == ":" then
if char == ':' then
if val1 == nil then
return nil, pos, "cannot use nil as table index (at " .. loc (str, pos) .. ")"
return nil, pos, 'cannot use nil as table index (at ' .. loc(str, pos) .. ')'
end
pos = scanwhite(str, pos + 1)
if not pos then return unterminated (str, what, startpos) end
if not pos then
return unterminated(str, what, startpos)
end
local val2
val2, pos, err = scanvalue(str, pos, nullval, objectmeta, arraymeta)
if err then return nil, pos, err end
if err then
return nil, pos, err
end
tbl[val1] = val2
pos = scanwhite(str, pos)
if not pos then return unterminated (str, what, startpos) end
if not pos then
return unterminated(str, what, startpos)
end
char = strsub(str, pos, pos)
else
n = n + 1
tbl[n] = val1
end
if char == "," then
if char == ',' then
pos = pos + 1
end
end
@ -557,40 +611,40 @@ scanvalue = function (str, pos, nullval, objectmeta, arraymeta)
pos = pos or 1
pos = scanwhite(str, pos)
if not pos then
return nil, strlen (str) + 1, "no valid JSON value (reached the end)"
return nil, strlen(str) + 1, 'no valid JSON value (reached the end)'
end
local char = strsub(str, pos, pos)
if char == "{" then
return scantable ('object', "}", str, pos, nullval, objectmeta, arraymeta)
elseif char == "[" then
return scantable ('array', "]", str, pos, nullval, objectmeta, arraymeta)
elseif char == "\"" then
if char == '{' then
return scantable('object', '}', str, pos, nullval, objectmeta, arraymeta)
elseif char == '[' then
return scantable('array', ']', str, pos, nullval, objectmeta, arraymeta)
elseif char == '"' then
return scanstring(str, pos)
else
local pstart, pend = strfind (str, "^%-?[%d%.]+[eE]?[%+%-]?%d*", pos)
local pstart, pend = strfind(str, '^%-?[%d%.]+[eE]?[%+%-]?%d*', pos)
if pstart then
local number = str2num(strsub(str, pstart, pend))
if number then
return number, pend + 1
end
end
pstart, pend = strfind (str, "^%a%w*", pos)
pstart, pend = strfind(str, '^%a%w*', pos)
if pstart then
local name = strsub(str, pstart, pend)
if name == "true" then
if name == 'true' then
return true, pend + 1
elseif name == "false" then
elseif name == 'false' then
return false, pend + 1
elseif name == "null" then
elseif name == 'null' then
return nullval, pend + 1
end
end
return nil, pos, "no valid JSON value at " .. loc (str, pos)
return nil, pos, 'no valid JSON value at ' .. loc(str, pos)
end
end
local function optionalmetatables(...)
if select("#", ...) > 0 then
if select('#', ...) > 0 then
return ...
else
return { __jsontype = 'object' }, { __jsontype = 'array' }
@ -603,10 +657,10 @@ function json.decode (str, pos, nullval, ...)
end
function json.use_lpeg()
local g = require ("lpeg")
local g = require('lpeg')
if g.version() == "0.11" then
error "due to a bug in LPeg 0.11, it cannot be used for JSON matching"
if g.version() == '0.11' then
error('due to a bug in LPeg 0.11, it cannot be used for JSON matching')
end
local pegmatch = g.match
@ -614,7 +668,7 @@ function json.use_lpeg ()
local function ErrorCall(str, pos, msg, state)
if not state.msg then
state.msg = msg .. " at " .. loc (str, pos)
state.msg = msg .. ' at ' .. loc(str, pos)
state.pos = pos
end
return false
@ -625,20 +679,20 @@ function json.use_lpeg ()
end
local function ErrorUnterminatedCall(str, pos, what, state)
return ErrorCall (str, pos - 1, "unterminated " .. what, state)
return ErrorCall(str, pos - 1, 'unterminated ' .. what, state)
end
local SingleLineComment = P"//" * (1 - S"\n\r")^0
local MultiLineComment = P"/*" * (1 - P"*/")^0 * P"*/"
local Space = (S" \n\r\t" + P"\239\187\191" + SingleLineComment + MultiLineComment)^0
local SingleLineComment = P('//') * (1 - S('\n\r')) ^ 0
local MultiLineComment = P('/*') * (1 - P('*/')) ^ 0 * P('*/')
local Space = (S(' \n\r\t') + P('\239\187\191') + SingleLineComment + MultiLineComment) ^ 0
local function ErrUnterminated(what)
return g.Cmt(g.Cc(what) * g.Carg(2), ErrorUnterminatedCall)
end
local PlainChar = 1 - S"\"\\\n\r"
local EscapeSequence = (P"\\" * g.C (S"\"\\/bfnrt" + Err "unsupported escape sequence")) / escapechars
local HexDigit = R("09", "af", "AF")
local PlainChar = 1 - S('"\\\n\r')
local EscapeSequence = (P('\\') * g.C(S('"\\/bfnrt') + Err('unsupported escape sequence'))) / escapechars
local HexDigit = R('09', 'af', 'AF')
local function UTF16Surrogate(_match, _pos, high, low)
high, low = tonumber(high, 16), tonumber(low, 16)
if 0xD800 <= high and high <= 0xDBff and 0xDC00 <= low and low <= 0xDFFF then
@ -650,15 +704,15 @@ function json.use_lpeg ()
local function UTF16BMP(hex)
return unichar(tonumber(hex, 16))
end
local U16Sequence = (P"\\u" * g.C (HexDigit * HexDigit * HexDigit * HexDigit))
local U16Sequence = (P('\\u') * g.C(HexDigit * HexDigit * HexDigit * HexDigit))
local UnicodeEscape = g.Cmt(U16Sequence * U16Sequence, UTF16Surrogate) + U16Sequence / UTF16BMP
local Char = UnicodeEscape + EscapeSequence + PlainChar
local String = P"\"" * (g.Cs (Char ^ 0) * P"\"" + ErrUnterminated "string")
local Integer = P"-"^(-1) * (P"0" + (R"19" * R"09"^0))
local Fractal = P"." * R"09"^0
local Exponent = (S"eE") * (S"+-")^(-1) * R"09"^1
local Number = (Integer * Fractal^(-1) * Exponent^(-1))/str2num
local Constant = P"true" * g.Cc (true) + P"false" * g.Cc (false) + P"null" * g.Carg (1)
local String = P('"') * (g.Cs(Char ^ 0) * P('"') + ErrUnterminated('string'))
local Integer = P('-') ^ -1 * (P('0') + (R('19') * R('09') ^ 0))
local Fractal = P('.') * R('09') ^ 0
local Exponent = (S('eE')) * (S('+-')) ^ -1 * R('09') ^ 1
local Number = (Integer * Fractal ^ -1 * Exponent ^ -1) / str2num
local Constant = P('true') * g.Cc(true) + P('false') * g.Cc(false) + P('null') * g.Carg(1)
local SimpleValue = Number + String + Constant
local ArrayContent, ObjectContent
@ -672,7 +726,7 @@ function json.use_lpeg ()
repeat
obj, cont, npos = pegmatch(ArrayContent, str, pos, nullval, state)
if cont == 'end' then
return ErrorUnterminatedCall (str, start, "array", state)
return ErrorUnterminatedCall(str, start, 'array', state)
end
pos = npos
if cont == 'cont' or cont == 'last' then
@ -691,7 +745,7 @@ function json.use_lpeg ()
repeat
key, obj, cont, npos = pegmatch(ObjectContent, str, pos, nullval, state)
if cont == 'end' then
return ErrorUnterminatedCall (str, start, "object", state)
return ErrorUnterminatedCall(str, start, 'object', state)
end
pos = npos
if cont == 'cont' or cont == 'last' then
@ -701,16 +755,23 @@ function json.use_lpeg ()
return pos, setmetatable(t, state.objectmeta)
end
local Array = P"[" * g.Cmt (g.Carg(1) * g.Carg(2), parsearray)
local Object = P"{" * g.Cmt (g.Carg(1) * g.Carg(2), parseobject)
local Array = P('[') * g.Cmt(g.Carg(1) * g.Carg(2), parsearray)
local Object = P('{') * g.Cmt(g.Carg(1) * g.Carg(2), parseobject)
local Value = Space * (Array + Object + SimpleValue)
local ExpectedValue = Value + Space * Err "value expected"
local ExpectedKey = String + Err "key expected"
local End = P(-1) * g.Cc'end'
local ErrInvalid = Err "invalid JSON"
ArrayContent = (Value * Space * (P"," * g.Cc'cont' + P"]" * g.Cc'last'+ End + ErrInvalid) + g.Cc(nil) * (P"]" * g.Cc'empty' + End + ErrInvalid)) * g.Cp()
local Pair = g.Cg (Space * ExpectedKey * Space * (P":" + Err "colon expected") * ExpectedValue)
ObjectContent = (g.Cc(nil) * g.Cc(nil) * P"}" * g.Cc'empty' + End + (Pair * Space * (P"," * g.Cc'cont' + P"}" * g.Cc'last' + End + ErrInvalid) + ErrInvalid)) * g.Cp()
local ExpectedValue = Value + Space * Err('value expected')
local ExpectedKey = String + Err('key expected')
local End = P(-1) * g.Cc('end')
local ErrInvalid = Err('invalid JSON')
ArrayContent = (
Value * Space * (P(',') * g.Cc('cont') + P(']') * g.Cc('last') + End + ErrInvalid)
+ g.Cc(nil) * (P(']') * g.Cc('empty') + End + ErrInvalid)
) * g.Cp()
local Pair = g.Cg(Space * ExpectedKey * Space * (P(':') + Err('colon expected')) * ExpectedValue)
ObjectContent = (
g.Cc(nil) * g.Cc(nil) * P('}') * g.Cc('empty')
+ End
+ (Pair * Space * (P(',') * g.Cc('cont') + P('}') * g.Cc('last') + End + ErrInvalid) + ErrInvalid)
) * g.Cp()
local DecodeValue = ExpectedValue * g.Cp()
jsonlpeg.version = json.version
@ -733,7 +794,9 @@ function json.use_lpeg ()
end
-- cache result of this function:
json.use_lpeg = function () return jsonlpeg end
json.use_lpeg = function()
return jsonlpeg
end
jsonlpeg.use_lpeg = json.use_lpeg
return jsonlpeg
@ -744,4 +807,3 @@ if always_use_lpeg then
end
return json

View File

@ -11,24 +11,26 @@
--]]
local awful = require("awful")
local awful = require('awful')
local sqrt = math.sqrt
local pairs = pairs
local client = client
local tonumber = tonumber
local wrequire = require("lain.helpers").wrequire
local wrequire = require('lain.helpers').wrequire
local setmetatable = setmetatable
-- Lain utilities submodule
-- lain.util
local util = { _NAME = "lain.util" }
local util = { _NAME = 'lain.util' }
-- Like awful.menu.clients, but only show clients of currently selected tags
function util.menu_clients_current_tags(menu, args)
-- List of currently selected tags.
local cls_tags = awful.screen.focused().selected_tags
if cls_tags == nil then return nil end
if cls_tags == nil then
return nil
end
-- Final list of menu items.
local cls_t = {}
@ -40,22 +42,28 @@ function util.menu_clients_current_tags(menu, args)
local cls = t:clients()
for _, c in pairs(cls) do
cls_t[#cls_t + 1] = { awful.util.escape(c.name) or "",
cls_t[#cls_t + 1] = {
awful.util.escape(c.name) or '',
function()
c.minimized = false
client.focus = c
c:raise()
end,
c.icon }
c.icon,
}
end
end
-- No clients? Then quit.
if #cls_t <= 0 then return nil end
if #cls_t <= 0 then
return nil
end
-- menu may contain some predefined values, otherwise start with a
-- fresh menu.
if not menu then menu = {} end
if not menu then
menu = {}
end
-- Set the list of items and show the menu.
menu.items = cls_t
@ -79,7 +87,9 @@ end
-- https://github.com/lcpz/lain/issues/195
function util.mc(c, width_f, height_f)
c = c or util.magnified_client
if not c then return end
if not c then
return
end
c.floating = true
local s = awful.screen.focused()
@ -91,7 +101,9 @@ function util.mc(c, width_f, height_f)
g.x = mg.x + (mg.width - g.width) / 2
g.y = mg.y + (mg.height - g.height) / 2
if c then c:geometry(g) end -- if c is still a valid object
if c then
c:geometry(g)
end -- if c is still a valid object
end
-- Non-empty tag browsing
@ -133,29 +145,35 @@ end
-- Add a new tag
function util.add_tag(layout)
awful.prompt.run {
prompt = "New tag name: ",
awful.prompt.run({
prompt = 'New tag name: ',
textbox = awful.screen.focused().mypromptbox.widget,
exe_callback = function(name)
if not name or #name == 0 then return end
awful.tag.add(name, { screen = awful.screen.focused(), layout = layout or awful.layout.suit.tile }):view_only()
if not name or #name == 0 then
return
end
}
awful.tag
.add(name, { screen = awful.screen.focused(), layout = layout or awful.layout.suit.tile })
:view_only()
end,
})
end
-- Rename current tag
function util.rename_tag()
awful.prompt.run {
prompt = "Rename tag: ",
awful.prompt.run({
prompt = 'Rename tag: ',
textbox = awful.screen.focused().mypromptbox.widget,
exe_callback = function(new_name)
if not new_name or #new_name == 0 then return end
if not new_name or #new_name == 0 then
return
end
local t = awful.screen.focused().selected_tag
if t then
t.name = new_name
end
end
}
end,
})
end
-- Move current tag
@ -173,7 +191,9 @@ end
-- Any rule set on the tag shall be broken
function util.delete_tag()
local t = awful.screen.focused().selected_tag
if not t then return end
if not t then
return
end
t:delete()
end

View File

@ -15,13 +15,27 @@ local setmetatable = setmetatable
local markup = { fg = {}, bg = {} }
-- Convenience tags
function markup.bold(text) return format("<b>%s</b>", text) end
function markup.italic(text) return format("<i>%s</i>", text) end
function markup.strike(text) return format("<s>%s</s>", text) end
function markup.underline(text) return format("<u>%s</u>", text) end
function markup.monospace(text) return format("<tt>%s</tt>", text) end
function markup.big(text) return format("<big>%s</big>", text) end
function markup.small(text) return format("<small>%s</small>", text) end
function markup.bold(text)
return format('<b>%s</b>', text)
end
function markup.italic(text)
return format('<i>%s</i>', text)
end
function markup.strike(text)
return format('<s>%s</s>', text)
end
function markup.underline(text)
return format('<u>%s</u>', text)
end
function markup.monospace(text)
return format('<tt>%s</tt>', text)
end
function markup.big(text)
return format('<big>%s</big>', text)
end
function markup.small(text)
return format('<small>%s</small>', text)
end
-- Set the font
function markup.font(font, text)
@ -59,8 +73,20 @@ function markup.fontcolor(font, fg, bg, text)
end
-- link markup.{fg,bg}(...) calls to markup.{fg,bg}.color(...)
setmetatable(markup.fg, { __call = function(_, ...) return markup.fg.color(...) end })
setmetatable(markup.bg, { __call = function(_, ...) return markup.bg.color(...) end })
setmetatable(markup.fg, {
__call = function(_, ...)
return markup.fg.color(...)
end,
})
setmetatable(markup.bg, {
__call = function(_, ...)
return markup.bg.color(...)
end,
})
-- link markup(...) calls to markup.fg.color(...)
return setmetatable(markup, { __call = function(_, ...) return markup.fg.color(...) end })
return setmetatable(markup, {
__call = function(_, ...)
return markup.fg.color(...)
end,
})

View File

@ -10,9 +10,9 @@
-- Menu iterator with Naughty notifications
-- lain.util.menu_iterator
local naughty = require("naughty")
local helpers = require("lain.helpers")
local atable = require("awful.util").table
local naughty = require('naughty')
local helpers = require('lain.helpers')
local atable = require('awful.util').table
local assert = assert
local pairs = pairs
local tconcat = table.concat
@ -27,7 +27,9 @@ local function naughty_destroy_callback(reason)
if actions then
for _, action in pairs(actions) do
-- don't try to call nil callbacks
if action then action() end
if action then
action()
end
end
state.index = nil
end
@ -56,7 +58,7 @@ local function iterate(menu, timeout, icon)
state.index = state.index + 1
if not next then
label = "Cancel"
label = 'Cancel'
state.index = nil
else
label, _ = unpack(next)
@ -68,7 +70,7 @@ local function iterate(menu, timeout, icon)
timeout = timeout,
screen = mouse.screen,
replaces_id = state.cid,
destroy = naughty_destroy_callback
destroy = naughty_destroy_callback,
}).id
end
@ -101,7 +103,8 @@ local function menu(args)
local rejected_cb = args.rejected_cb
local extra_choices = args.extra_choices or {}
local ch_combinations = args.combination == "powerset" and helpers.powerset(choices) or helpers.trivial_partition_set(choices)
local ch_combinations = args.combination == 'powerset' and helpers.powerset(choices)
or helpers.trivial_partition_set(choices)
for _, c in pairs(extra_choices) do
ch_combinations = atable.join(ch_combinations, { { c[1] } })
@ -116,14 +119,18 @@ local function menu(args)
-- selected choices
for _, ch in pairs(c) do
if atable.hasitem(choices, ch) then
cbs[#cbs + 1] = selected_cb and function() selected_cb(ch) end or nil
cbs[#cbs + 1] = selected_cb and function()
selected_cb(ch)
end or nil
end
end
-- rejected choices
for _, ch in pairs(choices) do
if not atable.hasitem(c, ch) and atable.hasitem(choices, ch) then
cbs[#cbs + 1] = rejected_cb and function() rejected_cb(ch) end or nil
cbs[#cbs + 1] = rejected_cb and function()
rejected_cb(ch)
end or nil
end
end
@ -134,7 +141,7 @@ local function menu(args)
end
end
m[#m + 1] = { name .. ": " .. tconcat(c, " + "), cbs }
m[#m + 1] = { name .. ': ' .. tconcat(c, ' + '), cbs }
end
end

View File

@ -6,7 +6,7 @@
--]]
local awful = require("awful")
local awful = require('awful')
local capi = { client = client }
local math = math
local string = string
@ -22,12 +22,15 @@ local quake = {}
-- run into problems with focus.
function quake:display()
if self.followtag then self.screen = awful.screen.focused() end
if self.followtag then
self.screen = awful.screen.focused()
end
-- First, we locate the client
local client = nil
local i = 0
for c in awful.client.iterate(function (c)
for c in
awful.client.iterate(function(c)
-- c.name may be changed!
return c.instance == self.name
end)
@ -46,12 +49,13 @@ function quake:display()
end
end
if not client and not self.visible then return end
if not client and not self.visible then
return
end
if not client then
-- The client does not exist, we spawn it
local cmd = string.format("%s %s %s", self.app,
string.format(self.argname, self.name), self.extra)
local cmd = string.format('%s %s %s', self.app, string.format(self.argname, self.name), self.extra)
awful.spawn(cmd, { tag = self.screen.selected_tag })
return
end
@ -71,7 +75,9 @@ function quake:display()
client.skip_taskbar = true
-- Additional user settings
if self.settings then self.settings(client) end
if self.settings then
self.settings(client)
end
-- Toggle display
if self.visible then
@ -108,22 +114,36 @@ function quake:compute_size()
geom = screen[self.screen.index].geometry
end
local width, height = self.width, self.height
if width <= 1 then width = math.floor(geom.width * width) - 2 * self.border end
if height <= 1 then height = math.floor(geom.height * height) end
if width <= 1 then
width = math.floor(geom.width * width) - 2 * self.border
end
if height <= 1 then
height = math.floor(geom.height * height)
end
local x, y
if self.horiz == "left" then x = geom.x
elseif self.horiz == "right" then x = geom.width + geom.x - width
else x = geom.x + (geom.width - width)/2 end
if self.vert == "top" then y = geom.y
elseif self.vert == "bottom" then y = geom.height + geom.y - height
else y = geom.y + (geom.height - height)/2 end
if self.horiz == 'left' then
x = geom.x
elseif self.horiz == 'right' then
x = geom.width + geom.x - width
else
x = geom.x + (geom.width - width) / 2
end
if self.vert == 'top' then
y = geom.y
elseif self.vert == 'bottom' then
y = geom.height + geom.y - height
else
y = geom.y + (geom.height - height) / 2
end
self.geometry[self.screen.index] = { x = x, y = y, width = width, height = height }
end
return self.geometry[self.screen.index]
end
function quake:toggle()
if self.followtag then self.screen = awful.screen.focused() end
if self.followtag then
self.screen = awful.screen.focused()
end
local current_tag = self.screen.selected_tag
if current_tag and self.last_tag ~= current_tag and self.visible then
local c = self:display()
@ -139,10 +159,10 @@ end
function quake.new(conf)
conf = conf or {}
conf.app = conf.app or "xterm" -- application to spawn
conf.name = conf.name or "QuakeDD" -- window name
conf.argname = conf.argname or "-name %s" -- how to specify window name
conf.extra = conf.extra or "" -- extra arguments
conf.app = conf.app or 'xterm' -- application to spawn
conf.name = conf.name or 'QuakeDD' -- window name
conf.argname = conf.argname or '-name %s' -- how to specify window name
conf.extra = conf.extra or '' -- extra arguments
conf.border = conf.border or 1 -- client border width
conf.visible = conf.visible or false -- initially not visible
conf.followtag = conf.followtag or false -- spawn on currently focused screen
@ -153,8 +173,8 @@ function quake.new(conf)
-- If width or height <= 1 this is a proportion of the workspace
conf.height = conf.height or 0.25 -- height
conf.width = conf.width or 1 -- width
conf.vert = conf.vert or "top" -- top, bottom or center
conf.horiz = conf.horiz or "left" -- left, right or center
conf.vert = conf.vert or 'top' -- top, bottom or center
conf.horiz = conf.horiz or 'left' -- left, right or center
conf.geometry = {} -- internal use
conf.maximized = false
@ -162,12 +182,12 @@ function quake.new(conf)
local dropdown = setmetatable(conf, { __index = quake })
capi.client.connect_signal("manage", function(c)
capi.client.connect_signal('manage', function(c)
if c.instance == dropdown.name and c.screen == dropdown.screen then
dropdown:display()
end
end)
capi.client.connect_signal("unmanage", function(c)
capi.client.connect_signal('unmanage', function(c)
if c.instance == dropdown.name and c.screen == dropdown.screen then
dropdown.visible = false
end
@ -176,4 +196,8 @@ function quake.new(conf)
return dropdown
end
return setmetatable(quake, { __call = function(_, ...) return quake.new(...) end })
return setmetatable(quake, {
__call = function(_, ...)
return quake.new(...)
end,
})

View File

@ -6,9 +6,9 @@
--]]
local wibox = require("wibox")
local gears = require("gears")
local beautiful = require("beautiful")
local wibox = require('wibox')
local gears = require('gears')
local beautiful = require('beautiful')
-- Lain Cairo separators util submodule
-- lain.util.separators
@ -29,11 +29,11 @@ function separators.arrow_right(col1, col2)
widget.update = function(_, _)
widget.col1 = col1
widget.col2 = col2
widget:emit_signal("widget::redraw_needed")
widget:emit_signal('widget::redraw_needed')
end
widget.draw = function(_, _, cr, width, height)
if widget.col2 ~= "alpha" then
if widget.col2 ~= 'alpha' then
cr:set_source_rgba(gears.color.parse_color(widget.col2))
cr:new_path()
cr:move_to(0, 0)
@ -50,7 +50,7 @@ function separators.arrow_right(col1, col2)
cr:fill()
end
if widget.col1 ~= "alpha" then
if widget.col1 ~= 'alpha' then
cr:set_source_rgba(gears.color.parse_color(widget.col1))
cr:new_path()
cr:move_to(0, 0)
@ -77,11 +77,11 @@ function separators.arrow_left(col1, col2)
widget.update = function(c1, c2)
widget.col1 = c1
widget.col2 = c2
widget:emit_signal("widget::redraw_needed")
widget:emit_signal('widget::redraw_needed')
end
widget.draw = function(_, _, cr, width, height)
if widget.col1 ~= "alpha" then
if widget.col1 ~= 'alpha' then
cr:set_source_rgba(gears.color.parse_color(widget.col1))
cr:new_path()
cr:move_to(width, 0)
@ -98,7 +98,7 @@ function separators.arrow_left(col1, col2)
cr:fill()
end
if widget.col2 ~= "alpha" then
if widget.col2 ~= 'alpha' then
cr:new_path()
cr:move_to(width, 0)
cr:line_to(0, height / 2)

View File

@ -6,9 +6,9 @@
--]]
local helpers = require("lain.helpers")
local shell = require("awful.util").shell
local wibox = require("wibox")
local helpers = require('lain.helpers')
local shell = require('awful.util').shell
local wibox = require('wibox')
local string = string
-- ALSA volume
@ -20,22 +20,25 @@ local function factory(args)
local timeout = args.timeout or 5
local settings = args.settings or function() end
alsa.cmd = args.cmd or "amixer"
alsa.channel = args.channel or "Master"
alsa.cmd = args.cmd or 'amixer'
alsa.channel = args.channel or 'Master'
alsa.togglechannel = args.togglechannel
local format_cmd = string.format("%s get %s", alsa.cmd, alsa.channel)
local format_cmd = string.format('%s get %s', alsa.cmd, alsa.channel)
if alsa.togglechannel then
format_cmd = { shell, "-c", string.format("%s get %s; %s get %s",
alsa.cmd, alsa.channel, alsa.cmd, alsa.togglechannel) }
format_cmd = {
shell,
'-c',
string.format('%s get %s; %s get %s', alsa.cmd, alsa.channel, alsa.cmd, alsa.togglechannel),
}
end
alsa.last = {}
function alsa.update()
helpers.async(format_cmd, function(mixer)
local l,s = string.match(mixer, "([%d]+)%%.*%[([%l]*)")
local l, s = string.match(mixer, '([%d]+)%%.*%[([%l]*)')
l = tonumber(l)
if alsa.last.level ~= l or alsa.last.status ~= s then
volume_now = { level = l, status = s }
@ -46,7 +49,7 @@ local function factory(args)
end)
end
helpers.newtimer(string.format("alsa-%s-%s", alsa.cmd, alsa.channel), timeout, alsa.update)
helpers.newtimer(string.format('alsa-%s-%s', alsa.cmd, alsa.channel), timeout, alsa.update)
return alsa
end

View File

@ -6,10 +6,10 @@
--]]
local helpers = require("lain.helpers")
local awful = require("awful")
local naughty = require("naughty")
local wibox = require("wibox")
local helpers = require('lain.helpers')
local awful = require('awful')
local naughty = require('naughty')
local wibox = require('wibox')
local math = math
local string = string
local type = type
@ -21,13 +21,13 @@ local tonumber = tonumber
local function factory(args)
local alsabar = {
colors = {
background = "#000000",
mute = "#EB8F8F",
unmute = "#A4CE8A"
background = '#000000',
mute = '#EB8F8F',
unmute = '#A4CE8A',
},
_current_level = 0,
_playback = "off"
_playback = 'off',
}
args = args or {}
@ -39,30 +39,33 @@ local function factory(args)
local margins = args.margins or 1
local ticks = args.ticks or false
local ticks_size = args.ticks_size or 7
local tick = args.tick or "|"
local tick_pre = args.tick_pre or "["
local tick_post = args.tick_post or "]"
local tick_none = args.tick_none or " "
local tick = args.tick or '|'
local tick_pre = args.tick_pre or '['
local tick_post = args.tick_post or ']'
local tick_none = args.tick_none or ' '
alsabar.cmd = args.cmd or "amixer"
alsabar.channel = args.channel or "Master"
alsabar.cmd = args.cmd or 'amixer'
alsabar.channel = args.channel or 'Master'
alsabar.togglechannel = args.togglechannel
alsabar.colors = args.colors or alsabar.colors
alsabar.followtag = args.followtag or false
alsabar.notification_preset = args.notification_preset
if not alsabar.notification_preset then
alsabar.notification_preset = { font = "Monospace 10" }
alsabar.notification_preset = { font = 'Monospace 10' }
end
local format_cmd = string.format("%s get %s", alsabar.cmd, alsabar.channel)
local format_cmd = string.format('%s get %s', alsabar.cmd, alsabar.channel)
if alsabar.togglechannel then
format_cmd = { awful.util.shell, "-c", string.format("%s get %s; %s get %s",
alsabar.cmd, alsabar.channel, alsabar.cmd, alsabar.togglechannel) }
format_cmd = {
awful.util.shell,
'-c',
string.format('%s get %s; %s get %s', alsabar.cmd, alsabar.channel, alsabar.cmd, alsabar.togglechannel),
}
end
alsabar.bar = wibox.widget {
alsabar.bar = wibox.widget({
color = alsabar.colors.unmute,
background_color = alsabar.colors.background,
forced_height = height,
@ -71,38 +74,42 @@ local function factory(args)
paddings = margins,
ticks = ticks,
ticks_size = ticks_size,
widget = wibox.widget.progressbar
}
widget = wibox.widget.progressbar,
})
alsabar.tooltip = awful.tooltip({ objects = { alsabar.bar } })
function alsabar.update(callback)
helpers.async(format_cmd, function(mixer)
local vol, playback = string.match(mixer, "([%d]+)%%.*%[([%l]*)")
local vol, playback = string.match(mixer, '([%d]+)%%.*%[([%l]*)')
if not vol or not playback then return end
if not vol or not playback then
return
end
if vol ~= alsabar._current_level or playback ~= alsabar._playback then
alsabar._current_level = tonumber(vol)
alsabar.bar:set_value(alsabar._current_level / 100)
if alsabar._current_level == 0 or playback == "off" then
if alsabar._current_level == 0 or playback == 'off' then
alsabar._playback = playback
alsabar.tooltip:set_text("[Muted]")
alsabar.tooltip:set_text('[Muted]')
alsabar.bar.color = alsabar.colors.mute
else
alsabar._playback = "on"
alsabar.tooltip:set_text(string.format("%s: %s", alsabar.channel, vol))
alsabar._playback = 'on'
alsabar.tooltip:set_text(string.format('%s: %s', alsabar.channel, vol))
alsabar.bar.color = alsabar.colors.unmute
end
volume_now = {
level = alsabar._current_level,
status = alsabar._playback
status = alsabar._playback,
}
settings()
if type(callback) == "function" then callback() end
if type(callback) == 'function' then
callback()
end
end
end)
end
@ -111,10 +118,10 @@ local function factory(args)
alsabar.update(function()
local preset = alsabar.notification_preset
preset.title = string.format("%s - %s%%", alsabar.channel, alsabar._current_level)
preset.title = string.format('%s - %s%%', alsabar.channel, alsabar._current_level)
if alsabar._playback == "off" then
preset.title = preset.title .. " Muted"
if alsabar._playback == 'off' then
preset.title = preset.title .. ' Muted'
end
-- tot is the maximum number of ticks to display in the notification
@ -125,7 +132,7 @@ local function factory(args)
-- if we can grab mywibox, tot is defined as its height if
-- horizontal, or width otherwise
if wib then
if wib.position == "left" or wib.position == "right" then
if wib.position == 'left' or wib.position == 'right' then
tot = wib.width
else
tot = wib.height
@ -137,28 +144,27 @@ local function factory(args)
end
local int = math.modf((alsabar._current_level / 100) * tot)
preset.text = string.format(
"%s%s%s%s",
tick_pre,
string.rep(tick, int),
string.rep(tick_none, tot - int),
tick_post
)
preset.text =
string.format('%s%s%s%s', tick_pre, string.rep(tick, int), string.rep(tick_none, tot - int), tick_post)
if alsabar.followtag then preset.screen = awful.screen.focused() end
if alsabar.followtag then
preset.screen = awful.screen.focused()
end
if not alsabar.notification then
alsabar.notification = naughty.notify {
alsabar.notification = naughty.notify({
preset = preset,
destroy = function() alsabar.notification = nil end
}
destroy = function()
alsabar.notification = nil
end,
})
else
naughty.replace_text(alsabar.notification, preset.title, preset.text)
end
end)
end
helpers.newtimer(string.format("alsabar-%s-%s", alsabar.cmd, alsabar.channel), timeout, alsabar.update)
helpers.newtimer(string.format('alsabar-%s-%s', alsabar.cmd, alsabar.channel), timeout, alsabar.update)
return alsabar
end

View File

@ -6,10 +6,10 @@
--]]
local helpers = require("lain.helpers")
local fs = require("gears.filesystem")
local naughty = require("naughty")
local wibox = require("wibox")
local helpers = require('lain.helpers')
local fs = require('gears.filesystem')
local naughty = require('naughty')
local wibox = require('wibox')
local math = math
local string = string
local ipairs = ipairs
@ -19,10 +19,10 @@ local tonumber = tonumber
-- lain.widget.bat
local function factory(args)
local pspath = args.pspath or "/sys/class/power_supply/"
local pspath = args.pspath or '/sys/class/power_supply/'
if not fs.is_dir(pspath) then
naughty.notify { text = "lain.widget.bat: invalid power supply path", timeout = 0 }
naughty.notify({ text = 'lain.widget.bat: invalid power supply path', timeout = 0 })
return
end
@ -30,64 +30,66 @@ local function factory(args)
local bat = { widget = args.widget or wibox.widget.textbox() }
local timeout = args.timeout or 30
local notify = args.notify or "on"
local notify = args.notify or 'on'
local full_notify = args.full_notify or notify
local n_perc = args.n_perc or { 5, 15 }
local batteries = args.batteries or (args.battery and { args.battery }) or {}
local ac = args.ac or "AC0"
local ac = args.ac or 'AC0'
local settings = args.settings or function() end
function bat.get_batteries()
helpers.line_callback("ls -1 " .. pspath, function(line)
local bstr = string.match(line, "BAT%w+")
helpers.line_callback('ls -1 ' .. pspath, function(line)
local bstr = string.match(line, 'BAT%w+')
if bstr then
batteries[#batteries + 1] = bstr
else
ac = string.match(line, "A%w+") or ac
ac = string.match(line, 'A%w+') or ac
end
end)
end
if #batteries == 0 then bat.get_batteries() end
if #batteries == 0 then
bat.get_batteries()
end
bat_notification_critical_preset = {
title = "Battery exhausted",
text = "Shutdown imminent",
title = 'Battery exhausted',
text = 'Shutdown imminent',
timeout = 15,
fg = "#000000",
bg = "#FFFFFF"
fg = '#000000',
bg = '#FFFFFF',
}
bat_notification_low_preset = {
title = "Battery low",
text = "Plug the cable!",
title = 'Battery low',
text = 'Plug the cable!',
timeout = 15,
fg = "#202020",
bg = "#CDCDCD"
fg = '#202020',
bg = '#CDCDCD',
}
bat_notification_charged_preset = {
title = "Battery full",
text = "You can unplug the cable",
title = 'Battery full',
text = 'You can unplug the cable',
timeout = 15,
fg = "#202020",
bg = "#CDCDCD"
fg = '#202020',
bg = '#CDCDCD',
}
bat_now = {
status = "N/A",
ac_status = "N/A",
perc = "N/A",
time = "N/A",
watt = "N/A",
capacity = "N/A"
status = 'N/A',
ac_status = 'N/A',
perc = 'N/A',
time = 'N/A',
watt = 'N/A',
capacity = 'N/A',
}
bat_now.n_status = {}
bat_now.n_perc = {}
bat_now.n_capacity = {}
for i = 1, #batteries do
bat_now.n_status[i] = "N/A"
bat_now.n_status[i] = 'N/A'
bat_now.n_perc[i] = 0
bat_now.n_capacity[i] = 0
end
@ -108,28 +110,27 @@ local function factory(args)
for i, battery in ipairs(batteries) do
local bstr = pspath .. battery
local present = helpers.first_line(bstr .. "/present")
local present = helpers.first_line(bstr .. '/present')
if tonumber(present) == 1 then
-- current_now(I)[uA], voltage_now(U)[uV], power_now(P)[uW]
local rate_current = tonumber(helpers.first_line(bstr .. "/current_now"))
local rate_voltage = tonumber(helpers.first_line(bstr .. "/voltage_now"))
local rate_power = tonumber(helpers.first_line(bstr .. "/power_now"))
local charge_full = tonumber(helpers.first_line(bstr .. "/charge_full"))
local charge_design = tonumber(helpers.first_line(bstr .. "/charge_full_design"))
local rate_current = tonumber(helpers.first_line(bstr .. '/current_now'))
local rate_voltage = tonumber(helpers.first_line(bstr .. '/voltage_now'))
local rate_power = tonumber(helpers.first_line(bstr .. '/power_now'))
local charge_full = tonumber(helpers.first_line(bstr .. '/charge_full'))
local charge_design = tonumber(helpers.first_line(bstr .. '/charge_full_design'))
-- energy_now(P)[uWh], charge_now(I)[uAh]
local energy_now = tonumber(helpers.first_line(bstr .. "/energy_now") or
helpers.first_line(bstr .. "/charge_now"))
local energy_now =
tonumber(helpers.first_line(bstr .. '/energy_now') or helpers.first_line(bstr .. '/charge_now'))
-- energy_full(P)[uWh], charge_full(I)[uAh]
local energy_full = tonumber(helpers.first_line(bstr .. "/energy_full") or
charge_full)
local energy_full = tonumber(helpers.first_line(bstr .. '/energy_full') or charge_full)
local energy_percentage = tonumber(helpers.first_line(bstr .. "/capacity")) or
math.floor((energy_now / energy_full) * 100)
local energy_percentage = tonumber(helpers.first_line(bstr .. '/capacity'))
or math.floor((energy_now / energy_full) * 100)
bat_now.n_status[i] = helpers.first_line(bstr .. "/status") or "N/A"
bat_now.n_status[i] = helpers.first_line(bstr .. '/status') or 'N/A'
bat_now.n_perc[i] = energy_percentage or bat_now.n_perc[i]
if not charge_design or charge_design == 0 then
@ -155,28 +156,28 @@ local function factory(args)
-- "Full", "Unknown" or "Charging". When the laptop is not plugged in,
-- one or more of the batteries may be full, but only one battery
-- discharging suffices to set global status to "Discharging".
bat_now.status = bat_now.n_status[1] or "N/A"
bat_now.status = bat_now.n_status[1] or 'N/A'
for _, status in ipairs(bat_now.n_status) do
if status == "Discharging" or status == "Charging" then
if status == 'Discharging' or status == 'Charging' then
bat_now.status = status
end
end
bat_now.ac_status = tonumber(helpers.first_line(string.format("%s%s/online", pspath, ac))) or "N/A"
bat_now.ac_status = tonumber(helpers.first_line(string.format('%s%s/online', pspath, ac))) or 'N/A'
if bat_now.status ~= "N/A" then
if bat_now.status ~= "Full" and sum_rate_power == 0 and bat_now.ac_status == 1 then
if bat_now.status ~= 'N/A' then
if bat_now.status ~= 'Full' and sum_rate_power == 0 and bat_now.ac_status == 1 then
bat_now.perc = math.floor(math.min(100, (sum_energy_now / sum_energy_full) * 100))
bat_now.time = "00:00"
bat_now.time = '00:00'
bat_now.watt = 0
-- update {perc,time,watt} iff battery not full and rate > 0
elseif bat_now.status ~= "Full" then
elseif bat_now.status ~= 'Full' then
local rate_time = 0
-- Calculate time and watt if rates are greater then 0
if (sum_rate_power > 0 or sum_rate_current > 0) then
if sum_rate_power > 0 or sum_rate_current > 0 then
local div = (sum_rate_power > 0 and sum_rate_power) or sum_rate_current
if bat_now.status == "Charging" then
if bat_now.status == 'Charging' then
rate_time = (sum_energy_full - sum_energy_now) / div
else -- Discharging
rate_time = sum_energy_now / div
@ -191,11 +192,11 @@ local function factory(args)
local hours = math.floor(rate_time)
local minutes = math.floor((rate_time - hours) * 60)
bat_now.perc = math.floor(math.min(100, (sum_energy_now / sum_energy_full) * 100))
bat_now.time = string.format("%02d:%02d", hours, minutes)
bat_now.watt = tonumber(string.format("%.2f", sum_rate_energy / 1e6))
elseif bat_now.status == "Full" then
bat_now.time = string.format('%02d:%02d', hours, minutes)
bat_now.watt = tonumber(string.format('%.2f', sum_rate_energy / 1e6))
elseif bat_now.status == 'Full' then
bat_now.perc = 100
bat_now.time = "00:00"
bat_now.time = '00:00'
bat_now.watt = 0
end
end
@ -204,31 +205,31 @@ local function factory(args)
settings()
-- notifications for critical, low, and full levels
if notify == "on" then
if bat_now.status == "Discharging" then
if notify == 'on' then
if bat_now.status == 'Discharging' then
if tonumber(bat_now.perc) <= n_perc[1] then
bat.id = naughty.notify({
preset = bat_notification_critical_preset,
replaces_id = bat.id
replaces_id = bat.id,
}).id
elseif tonumber(bat_now.perc) <= n_perc[2] then
bat.id = naughty.notify({
preset = bat_notification_low_preset,
replaces_id = bat.id
replaces_id = bat.id,
}).id
end
fullnotification = false
elseif bat_now.status == "Full" and full_notify == "on" and not fullnotification then
elseif bat_now.status == 'Full' and full_notify == 'on' and not fullnotification then
bat.id = naughty.notify({
preset = bat_notification_charged_preset,
replaces_id = bat.id
replaces_id = bat.id,
}).id
fullnotification = true
end
end
end
helpers.newtimer("batteries", timeout, bat.update)
helpers.newtimer('batteries', timeout, bat.update)
return bat
end

View File

@ -5,10 +5,10 @@
--]]
local helpers = require("lain.helpers")
local markup = require("lain.util.markup")
local awful = require("awful")
local naughty = require("naughty")
local helpers = require('lain.helpers')
local markup = require('lain.util.markup')
local awful = require('awful')
local naughty = require('naughty')
local floor = math.floor
local os = os
local pairs = pairs
@ -28,24 +28,28 @@ local function factory(args)
week_start = args.week_start or 2,
three = args.three or false,
followtag = args.followtag or false,
week_number = args.week_number or "none",
week_number_format = args.week_number_format or args.week_number == "left" and "%3d | " or "| %-3d",
icons = args.icons or helpers.icons_dir .. "cal/white/",
week_number = args.week_number or 'none',
week_number_format = args.week_number_format or args.week_number == 'left' and '%3d | ' or '| %-3d',
icons = args.icons or helpers.icons_dir .. 'cal/white/',
notification_preset = args.notification_preset or {
font = "Monospace 10", fg = "#FFFFFF", bg = "#000000"
}
font = 'Monospace 10',
fg = '#FFFFFF',
bg = '#000000',
},
}
function cal.get_week_number(m, st_day, x)
local date = os.date("*t", m)
local date = os.date('*t', m)
local week_step = (x ~= 0 and floor((x + st_day) / 7) - 1 or 0);
local week_step = (x ~= 0 and floor((x + st_day) / 7) - 1 or 0)
local display_time = os.time {
year = date.year, month = date.month, day = date.day + 7 * week_step
}
local display_time = os.time({
year = date.year,
month = date.month,
day = date.day + 7 * week_step,
})
return string.format(cal.week_number_format, os.date("%V", display_time))
return string.format(cal.week_number_format, os.date('%V', display_time))
end
function cal.sum_week_days(x, y)
@ -53,55 +57,70 @@ local function factory(args)
end
function cal.build(month, year)
local current_month, current_year = tonumber(os.date("%m")), tonumber(os.date("%Y"))
local current_month, current_year = tonumber(os.date('%m')), tonumber(os.date('%Y'))
local is_current_month = (not month or not year) or (month == current_month and year == current_year)
local today = is_current_month and tonumber(os.date("%d")) -- otherwise nil and not highlighted
local t = os.time { year = year or current_year, month = month and month+1 or current_month+1, day = 0 }
local d = os.date("*t", t)
local mth_days, st_day, this_month = d.day, (d.wday-d.day-cal.week_start+1)%7, os.date("%B %Y", t)
local notifytable = { [1] = string.format("%s%s\n", string.rep(" ", floor((28 - this_month:len())/2)), markup.bold(this_month)) }
local today = is_current_month and tonumber(os.date('%d')) -- otherwise nil and not highlighted
local t = os.time({ year = year or current_year, month = month and month + 1 or current_month + 1, day = 0 })
local d = os.date('*t', t)
local mth_days, st_day, this_month = d.day, (d.wday - d.day - cal.week_start + 1) % 7, os.date('%B %Y', t)
local notifytable = {
[1] = string.format('%s%s\n', string.rep(' ', floor((28 - this_month:len()) / 2)), markup.bold(this_month)),
}
for day_num = 0, 6 do
notifytable[#notifytable+1] = string.format("%3s ", os.date("%a", os.time { year = 2006, month = 1, day = day_num + cal.week_start }))
notifytable[#notifytable + 1] = string.format(
'%3s ',
os.date('%a', os.time({ year = 2006, month = 1, day = day_num + cal.week_start }))
)
end
notifytable[#notifytable] = string.format("%s\n%s", notifytable[#notifytable]:sub(1, -2), string.rep(" ", st_day*4))
notifytable[#notifytable] =
string.format('%s\n%s', notifytable[#notifytable]:sub(1, -2), string.rep(' ', st_day * 4))
local strx
for x = 1, mth_days do
strx = x
if x == today then
if x < 10 then x = " " .. x end
strx = markup.bold(markup.color(cal.notification_preset.bg, cal.notification_preset.fg, x) .. " ")
if x < 10 then
x = ' ' .. x
end
strx = string.format("%s%s", string.rep(" ", 3 - tostring(x):len()), strx)
notifytable[#notifytable+1] = string.format("%-4s%s", strx, (x+st_day)%7==0 and x ~= mth_days and "\n" or "")
strx = markup.bold(markup.color(cal.notification_preset.bg, cal.notification_preset.fg, x) .. ' ')
end
strx = string.format('%s%s', string.rep(' ', 3 - tostring(x):len()), strx)
notifytable[#notifytable + 1] =
string.format('%-4s%s', strx, (x + st_day) % 7 == 0 and x ~= mth_days and '\n' or '')
end
if string.len(cal.icons or '') > 0 and today then
cal.icon = cal.icons .. today .. '.png'
end
if string.len(cal.icons or "") > 0 and today then cal.icon = cal.icons .. today .. ".png" end
cal.month, cal.year = d.month, d.year
if cal.week_number ~= "none" then
local m = os.time { year = year or current_year, month = month and month or current_month, day = 1 }
local head_prepend = string.rep(" ", tostring(string.format(cal.week_number_format, 0)):len())
if cal.week_number ~= 'none' then
local m = os.time({ year = year or current_year, month = month and month or current_month, day = 1 })
local head_prepend = string.rep(' ', tostring(string.format(cal.week_number_format, 0)):len())
if cal.week_number == "left" then
if cal.week_number == 'left' then
notifytable[1] = head_prepend .. notifytable[1] -- month-year row
notifytable[2] = head_prepend .. notifytable[2] -- weekdays row
notifytable[8] = notifytable[8]:gsub("\n", "\n" .. cal.get_week_number(m, st_day, 0)) -- first week of the month
notifytable[8] = notifytable[8]:gsub('\n', '\n' .. cal.get_week_number(m, st_day, 0)) -- first week of the month
for x = 10, #notifytable do
if cal.sum_week_days(st_day, x) == 2 then
notifytable[x] = cal.get_week_number(m, st_day, x) .. notifytable[x]
end
end
elseif cal.week_number == "right" then
notifytable[8] = notifytable[8]:gsub("\n", head_prepend .. "\n") -- weekdays row
elseif cal.week_number == 'right' then
notifytable[8] = notifytable[8]:gsub('\n', head_prepend .. '\n') -- weekdays row
for x = 9, #notifytable do
if cal.sum_week_days(st_day, x) == 1 then
notifytable[x] = notifytable[x]:gsub("\n", cal.get_week_number(m, st_day, x - 7) .. "\n")
notifytable[x] = notifytable[x]:gsub('\n', cal.get_week_number(m, st_day, x - 7) .. '\n')
end
end
-- last week of the month
local end_days = cal.sum_week_days(st_day, mth_days)
if end_days ~= 0 then end_days = 7 - end_days end
notifytable[#notifytable] = notifytable[#notifytable] .. string.rep(" ", 4 * end_days) .. cal.get_week_number(m, st_day, mth_days + end_days)
if end_days ~= 0 then
end_days = 7 - end_days
end
notifytable[#notifytable] = notifytable[#notifytable]
.. string.rep(' ', 4 * end_days)
.. cal.get_week_number(m, st_day, mth_days + end_days)
end
end
@ -110,8 +129,8 @@ local function factory(args)
function cal.getdate(month, year, offset)
if not month or not year then
month = tonumber(os.date("%m"))
year = tonumber(os.date("%Y"))
month = tonumber(os.date('%m'))
year = tonumber(os.date('%Y'))
end
month = month + offset
@ -130,7 +149,9 @@ local function factory(args)
end
function cal.hide()
if not cal.notification then return end
if not cal.notification then
return
end
naughty.destroy(cal.notification)
cal.notification = nil
end
@ -142,9 +163,12 @@ local function factory(args)
local current_month, current_year = cal.month, cal.year
local prev_month, prev_year = cal.getdate(cal.month, cal.year, -1)
local next_month, next_year = cal.getdate(cal.month, cal.year, 1)
text = string.format("%s\n\n%s\n\n%s",
tconcat(cal.build(prev_month, prev_year)), text,
tconcat(cal.build(next_month, next_year)))
text = string.format(
'%s\n\n%s\n\n%s',
tconcat(cal.build(prev_month, prev_year)),
text,
tconcat(cal.build(next_month, next_year))
)
cal.month, cal.year = current_month, current_year
end
@ -154,36 +178,47 @@ local function factory(args)
return
end
cal.notification = naughty.notify {
cal.notification = naughty.notify({
preset = cal.notification_preset,
screen = cal.followtag and awful.screen.focused() or scr or 1,
icon = cal.icon,
timeout = type(seconds) == "number" and seconds or cal.notification_preset.timeout or 5,
text = text
}
timeout = type(seconds) == 'number' and seconds or cal.notification_preset.timeout or 5,
text = text,
})
end
function cal.hover_on() cal.show(0) end
function cal.hover_on()
cal.show(0)
end
function cal.move(offset)
offset = offset or 0
cal.month, cal.year = cal.getdate(cal.month, cal.year, offset)
cal.show(0, cal.month, cal.year)
end
function cal.prev() cal.move(-1) end
function cal.next() cal.move( 1) end
function cal.prev()
cal.move(-1)
end
function cal.next()
cal.move(1)
end
function cal.attach(widget)
widget:connect_signal("mouse::enter", cal.hover_on)
widget:connect_signal("mouse::leave", cal.hide)
widget:buttons(awful.util.table.join(
widget:connect_signal('mouse::enter', cal.hover_on)
widget:connect_signal('mouse::leave', cal.hide)
widget:buttons(
awful.util.table.join(
awful.button({}, 1, cal.prev),
awful.button({}, 3, cal.next),
awful.button({}, 2, cal.hover_on),
awful.button({}, 5, cal.prev),
awful.button({}, 4, cal.next)))
awful.button({}, 4, cal.next)
)
)
end
for _, widget in pairs(cal.attach_to) do cal.attach(widget) end
for _, widget in pairs(cal.attach_to) do
cal.attach(widget)
end
return cal
end

View File

@ -10,9 +10,9 @@
--]]
local wrequire = require("lain.helpers").wrequire
local wrequire = require('lain.helpers').wrequire
local setmetatable = setmetatable
local widget = { _NAME = "lain.widget.contrib" }
local widget = { _NAME = 'lain.widget.contrib' }
return setmetatable(widget, { __index = wrequire })

View File

@ -5,12 +5,12 @@
--]]
local helpers = require("lain.helpers")
local shell = require("awful.util").shell
local focused = require("awful.screen").focused
local escape_f = require("awful.util").escape
local naughty = require("naughty")
local wibox = require("wibox")
local helpers = require('lain.helpers')
local shell = require('awful.util').shell
local focused = require('awful.screen').focused
local escape_f = require('awful.util').escape
local naughty = require('naughty')
local wibox = require('wibox')
local os = os
local string = string
@ -22,52 +22,61 @@ local function factory(args)
local moc = { widget = args.widget or wibox.widget.textbox() }
local timeout = args.timeout or 2
local music_dir = args.music_dir or os.getenv("HOME") .. "/Music"
local cover_pattern = args.cover_pattern or "*\\.(jpg|jpeg|png|gif)$"
local music_dir = args.music_dir or os.getenv('HOME') .. '/Music'
local cover_pattern = args.cover_pattern or '*\\.(jpg|jpeg|png|gif)$'
local cover_size = args.cover_size or 100
local default_art = args.default_art or ""
local default_art = args.default_art or ''
local followtag = args.followtag or false
local settings = args.settings or function() end
moc_notification_preset = { title = "Now playing", timeout = 6 }
moc_notification_preset = { title = 'Now playing', timeout = 6 }
helpers.set_map("current moc track", nil)
helpers.set_map('current moc track', nil)
function moc.update()
helpers.async("mocp -i", function(f)
helpers.async('mocp -i', function(f)
moc_now = {
state = "N/A",
file = "N/A",
artist = "N/A",
title = "N/A",
album = "N/A",
elapsed = "N/A",
total = "N/A"
state = 'N/A',
file = 'N/A',
artist = 'N/A',
title = 'N/A',
album = 'N/A',
elapsed = 'N/A',
total = 'N/A',
}
for line in string.gmatch(f, "[^\n]+") do
for k, v in string.gmatch(line, "([%w]+):[%s](.*)$") do
if k == "State" then moc_now.state = v
elseif k == "File" then moc_now.file = v
elseif k == "Artist" then moc_now.artist = escape_f(v)
elseif k == "SongTitle" then moc_now.title = escape_f(v)
elseif k == "Album" then moc_now.album = escape_f(v)
elseif k == "CurrentTime" then moc_now.elapsed = escape_f(v)
elseif k == "TotalTime" then moc_now.total = escape_f(v)
for line in string.gmatch(f, '[^\n]+') do
for k, v in string.gmatch(line, '([%w]+):[%s](.*)$') do
if k == 'State' then
moc_now.state = v
elseif k == 'File' then
moc_now.file = v
elseif k == 'Artist' then
moc_now.artist = escape_f(v)
elseif k == 'SongTitle' then
moc_now.title = escape_f(v)
elseif k == 'Album' then
moc_now.album = escape_f(v)
elseif k == 'CurrentTime' then
moc_now.elapsed = escape_f(v)
elseif k == 'TotalTime' then
moc_now.total = escape_f(v)
end
end
end
moc_notification_preset.text = string.format("%s (%s) - %s\n%s", moc_now.artist,
moc_now.album, moc_now.total, moc_now.title)
moc_notification_preset.text =
string.format('%s (%s) - %s\n%s', moc_now.artist, moc_now.album, moc_now.total, moc_now.title)
widget = moc.widget
settings()
if moc_now.state == "PLAY" then
if moc_now.title ~= helpers.get_map("current moc track") then
helpers.set_map("current moc track", moc_now.title)
if moc_now.state == 'PLAY' then
if moc_now.title ~= helpers.get_map('current moc track') then
helpers.set_map('current moc track', moc_now.title)
if followtag then moc_notification_preset.screen = focused() end
if followtag then
moc_notification_preset.screen = focused()
end
local common = {
preset = moc_notification_preset,
@ -76,20 +85,21 @@ local function factory(args)
replaces_id = moc.id,
}
local path = string.format("%s/%s", music_dir, string.match(moc_now.file, ".*/"))
local cover = string.format("find '%s' -maxdepth 1 -type f | egrep -i -m1 '%s'", path, cover_pattern)
helpers.async({ shell, "-c", cover }, function(current_icon)
common.icon = current_icon:gsub("\n", "")
local path = string.format('%s/%s', music_dir, string.match(moc_now.file, '.*/'))
local cover =
string.format("find '%s' -maxdepth 1 -type f | egrep -i -m1 '%s'", path, cover_pattern)
helpers.async({ shell, '-c', cover }, function(current_icon)
common.icon = current_icon:gsub('\n', '')
moc.id = naughty.notify(common).id
end)
end
elseif moc_now.state ~= "PAUSE" then
helpers.set_map("current moc track", nil)
elseif moc_now.state ~= 'PAUSE' then
helpers.set_map('current moc track', nil)
end
end)
end
moc.timer = helpers.newtimer("moc", timeout, moc.update, true, true)
moc.timer = helpers.newtimer('moc', timeout, moc.update, true, true)
return moc
end

View File

@ -6,8 +6,8 @@
--]]
local async = require("lain.helpers").async
local awful = require("awful")
local async = require('lain.helpers').async
local awful = require('awful')
local execute = os.execute
local type = type
@ -16,20 +16,20 @@ local type = type
local redshift = { active = false, pid = nil }
function redshift.start()
execute("pkill redshift")
awful.spawn.with_shell("redshift -x") -- clear adjustments
redshift.pid = awful.spawn.with_shell("redshift")
execute('pkill redshift')
awful.spawn.with_shell('redshift -x') -- clear adjustments
redshift.pid = awful.spawn.with_shell('redshift')
redshift.active = true
if type(redshift.update_fun) == "function" then
if type(redshift.update_fun) == 'function' then
redshift.update_fun(redshift.active)
end
end
function redshift.toggle()
async({ awful.util.shell, "-c", string.format("ps -p %d -o pid=", redshift.pid) }, function(f)
async({ awful.util.shell, '-c', string.format('ps -p %d -o pid=', redshift.pid) }, function(f)
if f and #f > 0 then -- redshift is running
-- Sending -USR1 toggles redshift (See project website)
execute("pkill -USR1 redshift")
execute('pkill -USR1 redshift')
redshift.active = not redshift.active
else -- not started or killed, (re)start it
redshift.start()
@ -45,9 +45,13 @@ end
-- Use it to update widget text or icons on status change.
function redshift.attach(widget, fun)
redshift.update_fun = fun or function() end
if not redshift.pid then redshift.start() end
if not redshift.pid then
redshift.start()
end
if widget then
widget:buttons(awful.util.table.join(awful.button({}, 1, function () redshift.toggle() end)))
widget:buttons(awful.util.table.join(awful.button({}, 1, function()
redshift.toggle()
end)))
end
end

View File

@ -5,10 +5,10 @@
--]]
local helpers = require("lain.helpers")
local markup = require("lain.util").markup
local awful = require("awful")
local naughty = require("naughty")
local helpers = require('lain.helpers')
local markup = require('lain.util').markup
local awful = require('awful')
local naughty = require('naughty')
local mouse = mouse
-- Taskwarrior notification
@ -16,7 +16,9 @@ local mouse = mouse
local task = {}
function task.hide()
if not task.notification then return end
if not task.notification then
return
end
naughty.destroy(task.notification)
task.notification = nil
end
@ -24,7 +26,7 @@ end
function task.show(scr)
task.notification_preset.screen = task.followtag and awful.screen.focused() or scr or 1
helpers.async({ awful.util.shell, "-c", task.show_cmd }, function(f)
helpers.async({ awful.util.shell, '-c', task.show_cmd }, function(f)
local widget_focused = true
if mouse.current_widgets then
@ -39,53 +41,55 @@ function task.show(scr)
if widget_focused then
task.hide()
task.notification = naughty.notify {
task.notification = naughty.notify({
preset = task.notification_preset,
title = "task next",
text = markup.font(task.notification_preset.font,
awful.util.escape(f:gsub("\n*$", "")))
}
title = 'task next',
text = markup.font(task.notification_preset.font, awful.util.escape(f:gsub('\n*$', ''))),
})
end
end)
end
function task.prompt()
awful.prompt.run {
awful.prompt.run({
prompt = task.prompt_text,
textbox = awful.screen.focused().mypromptbox.widget,
exe_callback = function(t)
helpers.async(t, function(f)
naughty.notify {
naughty.notify({
preset = task.notification_preset,
title = t,
text = markup.font(task.notification_preset.font,
awful.util.escape(f:gsub("\n*$", "")))
}
text = markup.font(task.notification_preset.font, awful.util.escape(f:gsub('\n*$', ''))),
})
end)
end,
history_path = awful.util.getdir("cache") .. "/history_task"
}
history_path = awful.util.getdir('cache') .. '/history_task',
})
end
function task.attach(widget, args)
args = args or {}
task.show_cmd = args.show_cmd or "task next"
task.prompt_text = args.prompt_text or "Enter task command: "
task.show_cmd = args.show_cmd or 'task next'
task.prompt_text = args.prompt_text or 'Enter task command: '
task.followtag = args.followtag or false
task.notification_preset = args.notification_preset
task.widget = widget
if not task.notification_preset then
task.notification_preset = {
font = "Monospace 10",
icon = helpers.icons_dir .. "/taskwarrior.png"
font = 'Monospace 10',
icon = helpers.icons_dir .. '/taskwarrior.png',
}
end
if widget then
widget:connect_signal("mouse::enter", function () task.show() end)
widget:connect_signal("mouse::leave", function () task.hide() end)
widget:connect_signal('mouse::enter', function()
task.show()
end)
widget:connect_signal('mouse::leave', function()
task.hide()
end)
end
end

View File

@ -6,10 +6,10 @@
--]]
local helpers = require("lain.helpers")
local focused = require("awful.screen").focused
local naughty = require("naughty")
local wibox = require("wibox")
local helpers = require('lain.helpers')
local focused = require('awful.screen').focused
local naughty = require('naughty')
local wibox = require('wibox')
local string = string
local type = type
@ -19,77 +19,92 @@ local type = type
local function factory(apipath)
local tp_smapi = {
path = apipath or "/sys/devices/platform/smapi"
path = apipath or '/sys/devices/platform/smapi',
}
function tp_smapi.get(batid, feature)
return helpers.first_line(string.format("%s/%s/%s", tp_smapi.path, batid or "BAT0", feature or ""))
return helpers.first_line(string.format('%s/%s/%s', tp_smapi.path, batid or 'BAT0', feature or ''))
end
function tp_smapi.installed(batid)
return tp_smapi.get(batid, "installed") == "1"
return tp_smapi.get(batid, 'installed') == '1'
end
function tp_smapi.status(batid)
return tp_smapi.get(batid, "state")
return tp_smapi.get(batid, 'state')
end
function tp_smapi.percentage(batid)
return tp_smapi.get(batid, "remaining_percent")
return tp_smapi.get(batid, 'remaining_percent')
end
-- either running or charging time
function tp_smapi.time(batid)
local status = tp_smapi.status(batid)
local mins_left = tp_smapi.get(batid, string.match(string.lower(status), "discharging") and "remaining_running_time" or "remaining_charging_time")
if not string.find(mins_left, "^%d+") then return "N/A" end
return string.format("%02d:%02d", math.floor(mins_left / 60), mins_left % 60) -- HH:mm
local mins_left = tp_smapi.get(
batid,
string.match(string.lower(status), 'discharging') and 'remaining_running_time' or 'remaining_charging_time'
)
if not string.find(mins_left, '^%d+') then
return 'N/A'
end
return string.format('%02d:%02d', math.floor(mins_left / 60), mins_left % 60) -- HH:mm
end
function tp_smapi.hide()
if not tp_smapi.notification then return end
if not tp_smapi.notification then
return
end
naughty.destroy(tp_smapi.notification)
tp_smapi.notification = nil
end
function tp_smapi.show(batid, seconds, scr)
if not tp_smapi.installed(batid) then return end
if not tp_smapi.installed(batid) then
return
end
local mfgr = tp_smapi.get(batid, "manufacturer") or "no_mfgr"
local model = tp_smapi.get(batid, "model") or "no_model"
local chem = tp_smapi.get(batid, "chemistry") or "no_chem"
local status = tp_smapi.get(batid, "state")
local mfgr = tp_smapi.get(batid, 'manufacturer') or 'no_mfgr'
local model = tp_smapi.get(batid, 'model') or 'no_model'
local chem = tp_smapi.get(batid, 'chemistry') or 'no_chem'
local status = tp_smapi.get(batid, 'state')
local time = tp_smapi.time(batid)
local msg
if status and status ~= "idle" then
msg = string.format("[%s] %s %s", status, time ~= "N/A" and time or "unknown remaining time",
string.lower(status):gsub(" ", ""):gsub("\n", "") == "charging" and " until charged" or " remaining")
if status and status ~= 'idle' then
msg = string.format(
'[%s] %s %s',
status,
time ~= 'N/A' and time or 'unknown remaining time',
string.lower(status):gsub(' ', ''):gsub('\n', '') == 'charging' and ' until charged' or ' remaining'
)
else
msg = "On AC power"
msg = 'On AC power'
end
tp_smapi.hide()
tp_smapi.notification = naughty.notify {
title = string.format("%s: %s %s (%s)", batid, mfgr, model, chem),
tp_smapi.notification = naughty.notify({
title = string.format('%s: %s %s (%s)', batid, mfgr, model, chem),
text = msg,
timeout = type(seconds) == "number" and seconds or 0,
screen = scr or focused()
}
timeout = type(seconds) == 'number' and seconds or 0,
screen = scr or focused(),
})
end
function tp_smapi.create_widget(args)
args = args or {}
local pspath = args.pspath or "/sys/class/power_supply/"
local pspath = args.pspath or '/sys/class/power_supply/'
local batteries = args.batteries or (args.battery and { args.battery }) or {}
local timeout = args.timeout or 30
local settings = args.settings or function() end
if #batteries == 0 then
helpers.line_callback("ls -1 " .. pspath, function(line)
local bstr = string.match(line, "BAT%w+")
if bstr then batteries[#batteries + 1] = bstr end
helpers.line_callback('ls -1 ' .. pspath, function(line)
local bstr = string.match(line, 'BAT%w+')
if bstr then
batteries[#batteries + 1] = bstr
end
end)
end
@ -97,21 +112,23 @@ local function factory(apipath)
for _, battery in ipairs(batteries) do
if not tp_smapi.installed(battery) then
naughty.notify {
naughty.notify({
preset = naughty.config.critical,
title = "tp_smapi: error while creating widget",
text = string.format("battery %s is not installed", battery)
}
title = 'tp_smapi: error while creating widget',
text = string.format('battery %s is not installed', battery),
})
all_batteries_installed = false
break
end
end
if not all_batteries_installed then return end
if not all_batteries_installed then
return
end
tpbat = {
batteries = batteries,
widget = args.widget or wibox.widget.textbox()
widget = args.widget or wibox.widget.textbox(),
}
function tpbat.update()
@ -119,15 +136,15 @@ local function factory(apipath)
n_status = {},
n_perc = {},
n_time = {},
status = "N/A"
status = 'N/A',
}
for i = 1, #batteries do
tpbat_now.n_status[i] = tp_smapi.status(batteries[i]) or "N/A"
tpbat_now.n_status[i] = tp_smapi.status(batteries[i]) or 'N/A'
tpbat_now.n_perc[i] = tp_smapi.percentage(batteries[i])
tpbat_now.n_time[i] = tp_smapi.time(batteries[i]) or "N/A"
tpbat_now.n_time[i] = tp_smapi.time(batteries[i]) or 'N/A'
if not tpbat_now.n_status[i]:lower():match("full") then
if not tpbat_now.n_status[i]:lower():match('full') then
tpbat_now.status = tpbat_now.n_status[i]
end
end
@ -136,7 +153,7 @@ local function factory(apipath)
settings()
end
helpers.newtimer("thinkpad-batteries", timeout, tpbat.update)
helpers.newtimer('thinkpad-batteries', timeout, tpbat.update)
return tpbat
end

View File

@ -6,8 +6,8 @@
--]]
local helpers = require("lain.helpers")
local wibox = require("wibox")
local helpers = require('lain.helpers')
local wibox = require('wibox')
local math = math
local string = string
@ -25,15 +25,14 @@ local function factory(args)
-- Read the amount of time the CPUs have spent performing
-- different kinds of work. Read the first line of /proc/stat
-- which is the sum of all CPUs.
for index,time in pairs(helpers.lines_match("cpu","/proc/stat")) do
for index, time in pairs(helpers.lines_match('cpu', '/proc/stat')) do
local coreid = index - 1
local core = cpu.core[coreid] or
{ last_active = 0 , last_total = 0, usage = 0 }
local core = cpu.core[coreid] or { last_active = 0, last_total = 0, usage = 0 }
local at = 1
local idle = 0
local total = 0
for field in string.gmatch(time, "[%s]+([^%s]+)") do
for field in string.gmatch(time, '[%s]+([^%s]+)') do
-- 4 = idle, 5 = ioWait. Essentially, the CPUs have done
-- nothing during these times.
if at == 4 or at == 5 then
@ -67,7 +66,7 @@ local function factory(args)
settings()
end
helpers.newtimer("cpu", timeout, cpu.update)
helpers.newtimer('cpu', timeout, cpu.update)
return cpu
end

View File

@ -7,12 +7,12 @@
--]]
local helpers = require("lain.helpers")
local Gio = require("lgi").Gio
local focused = require("awful.screen").focused
local wibox = require("wibox")
local naughty = require("naughty")
local gears = require("gears")
local helpers = require('lain.helpers')
local Gio = require('lgi').Gio
local focused = require('awful.screen').focused
local wibox = require('wibox')
local naughty = require('naughty')
local gears = require('gears')
local math = math
local string = string
local tconcat = table.concat
@ -20,7 +20,7 @@ local type = type
local query_size = Gio.FILE_ATTRIBUTE_FILESYSTEM_SIZE
local query_free = Gio.FILE_ATTRIBUTE_FILESYSTEM_FREE
local query_used = Gio.FILE_ATTRIBUTE_FILESYSTEM_USED
local query = query_size .. "," .. query_free .. "," .. query_used
local query = query_size .. ',' .. query_free .. ',' .. query_used
-- File systems info
-- lain.widget.fs
@ -31,14 +31,21 @@ local function factory(args)
local fs = {
widget = args.widget or wibox.widget.textbox(),
units = {
[1] = "Kb", [2] = "Mb", [3] = "Gb",
[4] = "Tb", [5] = "Pb", [6] = "Eb",
[7] = "Zb", [8] = "Yb"
}
[1] = 'Kb',
[2] = 'Mb',
[3] = 'Gb',
[4] = 'Tb',
[5] = 'Pb',
[6] = 'Eb',
[7] = 'Zb',
[8] = 'Yb',
},
}
function fs.hide()
if not fs.notification then return end
if not fs.notification then
return
end
naughty.destroy(fs.notification)
fs.notification = nil
end
@ -47,17 +54,17 @@ local function factory(args)
fs.hide()
fs.update(function()
fs.notification_preset.screen = fs.followtag and focused() or scr or 1
fs.notification = naughty.notify {
fs.notification = naughty.notify({
preset = fs.notification_preset,
timeout = type(seconds) == "number" and seconds or 5
}
timeout = type(seconds) == 'number' and seconds or 5,
})
end)
end
local timeout = args.timeout or 600
local partition = args.partition
local threshold = args.threshold or 99
local showpopup = args.showpopup or "on"
local showpopup = args.showpopup or 'on'
local settings = args.settings or function() end
fs.followtag = args.followtag or false
@ -65,9 +72,9 @@ local function factory(args)
if not fs.notification_preset then
fs.notification_preset = {
font = "Monospace 10",
fg = "#FFFFFF",
bg = "#000000"
font = 'Monospace 10',
fg = '#FFFFFF',
bg = '#000000',
}
end
@ -94,7 +101,7 @@ local function factory(args)
percentage = math.floor(100 * used / size), -- used percentage
size = size / math.pow(1024, units),
used = used / math.pow(1024, units),
free = free / math.pow(1024, units)
free = free / math.pow(1024, units),
}
if fs_now[path].percentage > 0 then -- don't notify unused file systems
@ -113,22 +120,29 @@ local function factory(args)
if partition and fs_now[partition] and fs_now[partition].percentage >= threshold then
if not helpers.get_map(partition) then
naughty.notify {
naughty.notify({
preset = naughty.config.presets.critical,
title = "Warning",
text = string.format("%s is above %d%% (%d%%)", partition, threshold, fs_now[partition].percentage)
}
title = 'Warning',
text = string.format('%s is above %d%% (%d%%)', partition, threshold, fs_now[partition].percentage),
})
helpers.set_map(partition, true)
else
helpers.set_map(partition, false)
end
end
local fmt = "%-" .. tostring(pathlen) .. "s %4s\t%6s\t%6s\n"
local notifytable = { [1] = string.format(fmt, "path", "used", "free", "size") }
fmt = "\n%-" .. tostring(pathlen) .. "s %3s%%\t%6.2f\t%6.2f %s"
local fmt = '%-' .. tostring(pathlen) .. 's %4s\t%6s\t%6s\n'
local notifytable = { [1] = string.format(fmt, 'path', 'used', 'free', 'size') }
fmt = '\n%-' .. tostring(pathlen) .. 's %3s%%\t%6.2f\t%6.2f %s'
for _, path in ipairs(notifypaths) do
notifytable[#notifytable+1] = string.format(fmt, path, fs_now[path].percentage, fs_now[path].free, fs_now[path].size, fs_now[path].units)
notifytable[#notifytable + 1] = string.format(
fmt,
path,
fs_now[path].percentage,
fs_now[path].free,
fs_now[path].size,
fs_now[path].units
)
end
fs.notification_preset.text = tconcat(notifytable)
@ -137,18 +151,22 @@ local function factory(args)
function fs.update(callback)
Gio.Async.start(gears.protected_call.call)(function()
update_synced()
if type(callback) == "function" and callback then
if type(callback) == 'function' and callback then
callback()
end
end)
end
if showpopup == "on" then
fs.widget:connect_signal('mouse::enter', function () fs.show(0) end)
fs.widget:connect_signal('mouse::leave', function () fs.hide() end)
if showpopup == 'on' then
fs.widget:connect_signal('mouse::enter', function()
fs.show(0)
end)
fs.widget:connect_signal('mouse::leave', function()
fs.hide()
end)
end
helpers.newtimer(partition or "fs", timeout, fs.update)
helpers.newtimer(partition or 'fs', timeout, fs.update)
return fs
end

View File

@ -5,10 +5,10 @@
--]]
local helpers = require("lain.helpers")
local naughty = require("naughty")
local wibox = require("wibox")
local awful = require("awful")
local helpers = require('lain.helpers')
local naughty = require('naughty')
local wibox = require('wibox')
local awful = require('awful')
local string = string
local type = type
local tonumber = tonumber
@ -28,30 +28,34 @@ local function factory(args)
local pwdtimeout = args.pwdtimeout or 10
local is_plain = args.is_plain or false
local followtag = args.followtag or false
local notify = args.notify or "on"
local notify = args.notify or 'on'
local settings = args.settings or function() end
local head_command = "curl --connect-timeout 3 -fsm 3"
local head_command = 'curl --connect-timeout 3 -fsm 3'
local request = "-X 'STATUS INBOX (MESSAGES RECENT UNSEEN)'"
if not server or not mail or not password then return end
if not server or not mail or not password then
return
end
mail_notification_preset = {
icon = helpers.icons_dir .. "mail.png",
position = "top_left"
icon = helpers.icons_dir .. 'mail.png',
position = 'top_left',
}
helpers.set_map(mail, 0)
if not is_plain then
if type(password) == "string" or type(password) == "table" then
helpers.async(password, function(f) password = f:gsub("\n", "") end)
elseif type(password) == "function" then
imap.pwdtimer = helpers.newtimer(mail .. "-password", pwdtimeout, function()
if type(password) == 'string' or type(password) == 'table' then
helpers.async(password, function(f)
password = f:gsub('\n', '')
end)
elseif type(password) == 'function' then
imap.pwdtimer = helpers.newtimer(mail .. '-password', pwdtimeout, function()
local retrieved_password, try_again = password()
if not try_again then
imap.pwdtimer:stop() -- stop trying to retrieve
password = retrieved_password or "" -- failsafe
password = retrieved_password or '' -- failsafe
end
end, true, true)
end
@ -59,31 +63,48 @@ local function factory(args)
function imap.update()
-- do not update if the password has not been retrieved yet
if type(password) ~= "string" then return end
if type(password) ~= 'string' then
return
end
local curl = string.format("%s --url imaps://%s:%s/INBOX -u %s:'%s' %s -k",
head_command, server, port, mail, password, request)
local curl = string.format(
"%s --url imaps://%s:%s/INBOX -u %s:'%s' %s -k",
head_command,
server,
port,
mail,
password,
request
)
helpers.async(curl, function(f)
imap_now = { ["MESSAGES"] = 0, ["RECENT"] = 0, ["UNSEEN"] = 0 }
imap_now = { ['MESSAGES'] = 0, ['RECENT'] = 0, ['UNSEEN'] = 0 }
for s,d in f:gmatch("(%w+)%s+(%d+)") do imap_now[s] = tonumber(d) end
mailcount = imap_now["UNSEEN"] -- backwards compatibility
for s, d in f:gmatch('(%w+)%s+(%d+)') do
imap_now[s] = tonumber(d)
end
mailcount = imap_now['UNSEEN'] -- backwards compatibility
widget = imap.widget
settings()
if notify == "on" and mailcount and mailcount >= 1 and mailcount > helpers.get_map(mail) then
if followtag then mail_notification_preset.screen = awful.screen.focused() end
naughty.notify {
if notify == 'on' and mailcount and mailcount >= 1 and mailcount > helpers.get_map(mail) then
if followtag then
mail_notification_preset.screen = awful.screen.focused()
end
naughty.notify({
preset = mail_notification_preset,
text = string.format("%s has <b>%d</b> new message%s", mail, mailcount, mailcount == 1 and "" or "s")
}
text = string.format(
'%s has <b>%d</b> new message%s',
mail,
mailcount,
mailcount == 1 and '' or 's'
),
})
end
helpers.set_map(mail, imap_now["UNSEEN"])
helpers.set_map(mail, imap_now['UNSEEN'])
end)
end
imap.timer = helpers.newtimer(mail, timeout, imap.update, true, true)

View File

@ -11,9 +11,9 @@
--]]
local wrequire = require("lain.helpers").wrequire
local wrequire = require('lain.helpers').wrequire
local setmetatable = setmetatable
local widget = { _NAME = "lain.widget" }
local widget = { _NAME = 'lain.widget' }
return setmetatable(widget, { __index = wrequire })

View File

@ -6,8 +6,8 @@
--]]
local helpers = require("lain.helpers")
local wibox = require("wibox")
local helpers = require('lain.helpers')
local wibox = require('wibox')
local gmatch, lines, floor = string.gmatch, io.lines, math.floor
-- Memory usage (ignoring caches)
@ -22,15 +22,22 @@ local function factory(args)
function mem.update()
mem_now = {}
for line in lines("/proc/meminfo") do
for k, v in gmatch(line, "([%a]+):[%s]+([%d]+).+") do
if k == "MemTotal" then mem_now.total = floor(v / 1024 + 0.5)
elseif k == "MemFree" then mem_now.free = floor(v / 1024 + 0.5)
elseif k == "Buffers" then mem_now.buf = floor(v / 1024 + 0.5)
elseif k == "Cached" then mem_now.cache = floor(v / 1024 + 0.5)
elseif k == "SwapTotal" then mem_now.swap = floor(v / 1024 + 0.5)
elseif k == "SwapFree" then mem_now.swapf = floor(v / 1024 + 0.5)
elseif k == "SReclaimable" then mem_now.srec = floor(v / 1024 + 0.5)
for line in lines('/proc/meminfo') do
for k, v in gmatch(line, '([%a]+):[%s]+([%d]+).+') do
if k == 'MemTotal' then
mem_now.total = floor(v / 1024 + 0.5)
elseif k == 'MemFree' then
mem_now.free = floor(v / 1024 + 0.5)
elseif k == 'Buffers' then
mem_now.buf = floor(v / 1024 + 0.5)
elseif k == 'Cached' then
mem_now.cache = floor(v / 1024 + 0.5)
elseif k == 'SwapTotal' then
mem_now.swap = floor(v / 1024 + 0.5)
elseif k == 'SwapFree' then
mem_now.swapf = floor(v / 1024 + 0.5)
elseif k == 'SReclaimable' then
mem_now.srec = floor(v / 1024 + 0.5)
end
end
end
@ -43,7 +50,7 @@ local function factory(args)
settings()
end
helpers.newtimer("mem", timeout, mem.update)
helpers.newtimer('mem', timeout, mem.update)
return mem
end

View File

@ -6,12 +6,12 @@
--]]
local helpers = require("lain.helpers")
local shell = require("awful.util").shell
local escape_f = require("awful.util").escape
local focused = require("awful.screen").focused
local naughty = require("naughty")
local wibox = require("wibox")
local helpers = require('lain.helpers')
local shell = require('awful.util').shell
local escape_f = require('awful.util').escape
local focused = require('awful.screen').focused
local naughty = require('naughty')
local wibox = require('wibox')
local os = os
local string = string
@ -23,111 +23,135 @@ local function factory(args)
local mpd = { widget = args.widget or wibox.widget.textbox() }
local timeout = args.timeout or 2
local password = (args.password and #args.password > 0 and string.format("password %s\\n", args.password)) or ""
local host = args.host or os.getenv("MPD_HOST") or "127.0.0.1"
local port = args.port or os.getenv("MPD_PORT") or "6600"
local music_dir = args.music_dir or os.getenv("HOME") .. "/Music"
local cover_pattern = args.cover_pattern or "*\\.(jpg|jpeg|png|gif)$"
local password = (args.password and #args.password > 0 and string.format('password %s\\n', args.password)) or ''
local host = args.host or os.getenv('MPD_HOST') or '127.0.0.1'
local port = args.port or os.getenv('MPD_PORT') or '6600'
local music_dir = args.music_dir or os.getenv('HOME') .. '/Music'
local cover_pattern = args.cover_pattern or '*\\.(jpg|jpeg|png|gif)$'
local cover_size = args.cover_size or 100
local default_art = args.default_art
local notify = args.notify or "on"
local notify = args.notify or 'on'
local followtag = args.followtag or false
local settings = args.settings or function() end
local mpdh = string.format("telnet://%s:%s", host, port)
local echo = string.format("printf \"%sstatus\\ncurrentsong\\nclose\\n\"", password)
local cmd = string.format("%s | curl --connect-timeout 1 -fsm 3 %s", echo, mpdh)
local mpdh = string.format('telnet://%s:%s', host, port)
local echo = string.format('printf "%sstatus\\ncurrentsong\\nclose\\n"', password)
local cmd = string.format('%s | curl --connect-timeout 1 -fsm 3 %s', echo, mpdh)
mpd_notification_preset = { title = "Now playing", timeout = 6 }
mpd_notification_preset = { title = 'Now playing', timeout = 6 }
helpers.set_map("current mpd track", nil)
helpers.set_map('current mpd track', nil)
function mpd.update()
helpers.async({ shell, "-c", cmd }, function(f)
helpers.async({ shell, '-c', cmd }, function(f)
mpd_now = {
random_mode = false,
single_mode = false,
repeat_mode = false,
consume_mode = false,
pls_pos = "N/A",
pls_len = "N/A",
state = "N/A",
file = "N/A",
name = "N/A",
artist = "N/A",
title = "N/A",
album = "N/A",
genre = "N/A",
track = "N/A",
date = "N/A",
time = "N/A",
elapsed = "N/A",
volume = "N/A"
pls_pos = 'N/A',
pls_len = 'N/A',
state = 'N/A',
file = 'N/A',
name = 'N/A',
artist = 'N/A',
title = 'N/A',
album = 'N/A',
genre = 'N/A',
track = 'N/A',
date = 'N/A',
time = 'N/A',
elapsed = 'N/A',
volume = 'N/A',
}
for line in string.gmatch(f, "[^\n]+") do
for k, v in string.gmatch(line, "([%w]+):[%s](.*)$") do
if k == "state" then mpd_now.state = v
elseif k == "file" then mpd_now.file = v
elseif k == "Name" then mpd_now.name = escape_f(v)
elseif k == "Artist" then mpd_now.artist = escape_f(v)
elseif k == "Title" then mpd_now.title = escape_f(v)
elseif k == "Album" then mpd_now.album = escape_f(v)
elseif k == "Genre" then mpd_now.genre = escape_f(v)
elseif k == "Track" then mpd_now.track = escape_f(v)
elseif k == "Date" then mpd_now.date = escape_f(v)
elseif k == "Time" then mpd_now.time = v
elseif k == "elapsed" then mpd_now.elapsed = string.match(v, "%d+")
elseif k == "song" then mpd_now.pls_pos = v
elseif k == "playlistlength" then mpd_now.pls_len = v
elseif k == "repeat" then mpd_now.repeat_mode = v ~= "0"
elseif k == "single" then mpd_now.single_mode = v ~= "0"
elseif k == "random" then mpd_now.random_mode = v ~= "0"
elseif k == "consume" then mpd_now.consume_mode = v ~= "0"
elseif k == "volume" then mpd_now.volume = v
for line in string.gmatch(f, '[^\n]+') do
for k, v in string.gmatch(line, '([%w]+):[%s](.*)$') do
if k == 'state' then
mpd_now.state = v
elseif k == 'file' then
mpd_now.file = v
elseif k == 'Name' then
mpd_now.name = escape_f(v)
elseif k == 'Artist' then
mpd_now.artist = escape_f(v)
elseif k == 'Title' then
mpd_now.title = escape_f(v)
elseif k == 'Album' then
mpd_now.album = escape_f(v)
elseif k == 'Genre' then
mpd_now.genre = escape_f(v)
elseif k == 'Track' then
mpd_now.track = escape_f(v)
elseif k == 'Date' then
mpd_now.date = escape_f(v)
elseif k == 'Time' then
mpd_now.time = v
elseif k == 'elapsed' then
mpd_now.elapsed = string.match(v, '%d+')
elseif k == 'song' then
mpd_now.pls_pos = v
elseif k == 'playlistlength' then
mpd_now.pls_len = v
elseif k == 'repeat' then
mpd_now.repeat_mode = v ~= '0'
elseif k == 'single' then
mpd_now.single_mode = v ~= '0'
elseif k == 'random' then
mpd_now.random_mode = v ~= '0'
elseif k == 'consume' then
mpd_now.consume_mode = v ~= '0'
elseif k == 'volume' then
mpd_now.volume = v
end
end
end
mpd_notification_preset.text = string.format("%s (%s) - %s\n%s", mpd_now.artist,
mpd_now.album, mpd_now.date, mpd_now.title)
mpd_notification_preset.text =
string.format('%s (%s) - %s\n%s', mpd_now.artist, mpd_now.album, mpd_now.date, mpd_now.title)
widget = mpd.widget
settings()
if mpd_now.state == "play" then
if notify == "on" and mpd_now.title ~= helpers.get_map("current mpd track") then
helpers.set_map("current mpd track", mpd_now.title)
if mpd_now.state == 'play' then
if notify == 'on' and mpd_now.title ~= helpers.get_map('current mpd track') then
helpers.set_map('current mpd track', mpd_now.title)
if followtag then mpd_notification_preset.screen = focused() end
if followtag then
mpd_notification_preset.screen = focused()
end
local common = {
preset = mpd_notification_preset,
icon = default_art,
icon_size = cover_size,
replaces_id = mpd.id
replaces_id = mpd.id,
}
if not string.match(mpd_now.file, "http.*://") then -- local file instead of http stream
local path = string.format("%s/%s", music_dir, string.match(mpd_now.file, ".*/"))
local cover = string.format("find '%s' -maxdepth 1 -type f | egrep -i -m1 '%s'",
path:gsub("'", "'\\''"), cover_pattern)
helpers.async({ shell, "-c", cover }, function(current_icon)
common.icon = current_icon:gsub("\n", "")
if #common.icon == 0 then common.icon = nil end
if not string.match(mpd_now.file, 'http.*://') then -- local file instead of http stream
local path = string.format('%s/%s', music_dir, string.match(mpd_now.file, '.*/'))
local cover = string.format(
"find '%s' -maxdepth 1 -type f | egrep -i -m1 '%s'",
path:gsub("'", "'\\''"),
cover_pattern
)
helpers.async({ shell, '-c', cover }, function(current_icon)
common.icon = current_icon:gsub('\n', '')
if #common.icon == 0 then
common.icon = nil
end
mpd.id = naughty.notify(common).id
end)
else
mpd.id = naughty.notify(common).id
end
end
elseif mpd_now.state ~= "pause" then
helpers.set_map("current mpd track", nil)
elseif mpd_now.state ~= 'pause' then
helpers.set_map('current mpd track', nil)
end
end)
end
mpd.timer = helpers.newtimer("mpd", timeout, mpd.update, true, true)
mpd.timer = helpers.newtimer('mpd', timeout, mpd.update, true, true)
return mpd
end

View File

@ -6,9 +6,9 @@
--]]
local helpers = require("lain.helpers")
local naughty = require("naughty")
local wibox = require("wibox")
local helpers = require('lain.helpers')
local naughty = require('naughty')
local wibox = require('wibox')
local string = string
-- Network infos
@ -20,25 +20,29 @@ local function factory(args)
local net = { widget = args.widget or wibox.widget.textbox(), devices = {} }
local timeout = args.timeout or 2
local units = args.units or 1024 -- KB
local notify = args.notify or "on"
local wifi_state = args.wifi_state or "off"
local eth_state = args.eth_state or "off"
local notify = args.notify or 'on'
local wifi_state = args.wifi_state or 'off'
local eth_state = args.eth_state or 'off'
local screen = args.screen or 1
local format = args.format or "%.1f"
local format = args.format or '%.1f'
local settings = args.settings or function() end
-- Compatibility with old API where iface was a string corresponding to 1 interface
net.iface = (args.iface and (type(args.iface) == "string" and {args.iface}) or
(type(args.iface) == "table" and args.iface)) or {}
net.iface = (
args.iface and (type(args.iface) == 'string' and { args.iface })
or (type(args.iface) == 'table' and args.iface)
) or {}
function net.get_devices()
net.iface = {} -- reset at every call
helpers.line_callback("ip link", function(line)
net.iface[#net.iface + 1] = not string.match(line, "LOOPBACK") and string.match(line, "(%w+): <") or nil
helpers.line_callback('ip link', function(line)
net.iface[#net.iface + 1] = not string.match(line, 'LOOPBACK') and string.match(line, '(%w+): <') or nil
end)
end
if #net.iface == 0 then net.get_devices() end
if #net.iface == 0 then
net.get_devices()
end
function net.update()
-- These are the totals over all specified interfaces
@ -46,17 +50,17 @@ local function factory(args)
devices = {},
-- Bytes since last iteration
sent = 0,
received = 0
received = 0,
}
for _, dev in ipairs(net.iface) do
local dev_now = {}
local dev_before = net.devices[dev] or { last_t = 0, last_r = 0 }
local now_t = tonumber(helpers.first_line(string.format("/sys/class/net/%s/statistics/tx_bytes", dev)) or 0)
local now_r = tonumber(helpers.first_line(string.format("/sys/class/net/%s/statistics/rx_bytes", dev)) or 0)
local now_t = tonumber(helpers.first_line(string.format('/sys/class/net/%s/statistics/tx_bytes', dev)) or 0)
local now_r = tonumber(helpers.first_line(string.format('/sys/class/net/%s/statistics/rx_bytes', dev)) or 0)
dev_now.carrier = helpers.first_line(string.format("/sys/class/net/%s/carrier", dev)) or "0"
dev_now.state = helpers.first_line(string.format("/sys/class/net/%s/operstate", dev)) or "down"
dev_now.carrier = helpers.first_line(string.format('/sys/class/net/%s/carrier', dev)) or '0'
dev_now.state = helpers.first_line(string.format('/sys/class/net/%s/operstate', dev)) or 'down'
dev_now.sent = (now_t - dev_before.last_t) / timeout / units
dev_now.received = (now_r - dev_before.last_r) / timeout / units
@ -70,16 +74,23 @@ local function factory(args)
dev_now.last_t = now_t
dev_now.last_r = now_r
if wifi_state == "on" and helpers.first_line(string.format("/sys/class/net/%s/uevent", dev)) == "DEVTYPE=wlan" then
if
wifi_state == 'on'
and helpers.first_line(string.format('/sys/class/net/%s/uevent', dev)) == 'DEVTYPE=wlan'
then
dev_now.wifi = true
if string.match(dev_now.carrier, "1") then
dev_now.signal = tonumber(string.match(helpers.lines_from("/proc/net/wireless")[3], "(%-%d+%.)")) or nil
if string.match(dev_now.carrier, '1') then
dev_now.signal = tonumber(string.match(helpers.lines_from('/proc/net/wireless')[3], '(%-%d+%.)'))
or nil
end
else
dev_now.wifi = false
end
if eth_state == "on" and helpers.first_line(string.format("/sys/class/net/%s/uevent", dev)) ~= "DEVTYPE=wlan" then
if
eth_state == 'on'
and helpers.first_line(string.format('/sys/class/net/%s/uevent', dev)) ~= 'DEVTYPE=wlan'
then
dev_now.ethernet = true
else
dev_now.ethernet = false
@ -88,15 +99,15 @@ local function factory(args)
net.devices[dev] = dev_now
-- Notify only once when connection is lost
if string.match(dev_now.carrier, "0") and notify == "on" and helpers.get_map(dev) then
naughty.notify {
if string.match(dev_now.carrier, '0') and notify == 'on' and helpers.get_map(dev) then
naughty.notify({
title = dev,
text = "No carrier",
icon = helpers.icons_dir .. "no_net.png",
screen = screen
}
text = 'No carrier',
icon = helpers.icons_dir .. 'no_net.png',
screen = screen,
})
helpers.set_map(dev, false)
elseif string.match(dev_now.carrier, "1") then
elseif string.match(dev_now.carrier, '1') then
helpers.set_map(dev, true)
end
@ -114,7 +125,7 @@ local function factory(args)
settings()
end
helpers.newtimer("network", timeout, net.update)
helpers.newtimer('network', timeout, net.update)
return net
end

View File

@ -5,9 +5,9 @@
--]]
local helpers = require("lain.helpers")
local shell = require("awful.util").shell
local wibox = require("wibox")
local helpers = require('lain.helpers')
local shell = require('awful.util').shell
local wibox = require('wibox')
local string = string
local type = type
@ -17,40 +17,42 @@ local type = type
local function factory(args)
args = args or {}
local pulse = { widget = args.widget or wibox.widget.textbox(), device = "N/A" }
local pulse = { widget = args.widget or wibox.widget.textbox(), device = 'N/A' }
local timeout = args.timeout or 5
local settings = args.settings or function() end
pulse.devicetype = args.devicetype or "sink"
pulse.cmd = args.cmd or "pacmd list-" .. pulse.devicetype .. "s | sed -n -e '/*/,$!d' -e '/index/p' -e '/base volume/d' -e '/volume:/p' -e '/muted:/p' -e '/device\\.string/p'"
pulse.devicetype = args.devicetype or 'sink'
pulse.cmd = args.cmd
or 'pacmd list-'
.. pulse.devicetype
.. "s | sed -n -e '/*/,$!d' -e '/index/p' -e '/base volume/d' -e '/volume:/p' -e '/muted:/p' -e '/device\\.string/p'"
function pulse.update()
helpers.async({ shell, "-c", type(pulse.cmd) == "string" and pulse.cmd or pulse.cmd() },
function(s)
helpers.async({ shell, '-c', type(pulse.cmd) == 'string' and pulse.cmd or pulse.cmd() }, function(s)
volume_now = {
index = string.match(s, "index: (%S+)") or "N/A",
device = string.match(s, "device.string = \"(%S+)\"") or "N/A",
muted = string.match(s, "muted: (%S+)") or "N/A"
index = string.match(s, 'index: (%S+)') or 'N/A',
device = string.match(s, 'device.string = "(%S+)"') or 'N/A',
muted = string.match(s, 'muted: (%S+)') or 'N/A',
}
pulse.device = volume_now.index
local ch = 1
volume_now.channel = {}
for v in string.gmatch(s, ":.-(%d+)%%") do
for v in string.gmatch(s, ':.-(%d+)%%') do
volume_now.channel[ch] = v
ch = ch + 1
end
volume_now.left = volume_now.channel[1] or "N/A"
volume_now.right = volume_now.channel[2] or "N/A"
volume_now.left = volume_now.channel[1] or 'N/A'
volume_now.right = volume_now.channel[2] or 'N/A'
widget = pulse.widget
settings()
end)
end
helpers.newtimer("pulse", timeout, pulse.update)
helpers.newtimer('pulse', timeout, pulse.update)
return pulse
end

View File

@ -6,10 +6,10 @@
--]]
local helpers = require("lain.helpers")
local awful = require("awful")
local naughty = require("naughty")
local wibox = require("wibox")
local helpers = require('lain.helpers')
local awful = require('awful')
local naughty = require('naughty')
local wibox = require('wibox')
local math = math
local string = string
local type = type
@ -21,15 +21,15 @@ local tonumber = tonumber
local function factory(args)
local pulsebar = {
colors = {
background = "#000000",
mute_background = "#000000",
mute = "#EB8F8F",
unmute = "#A4CE8A"
background = '#000000',
mute_background = '#000000',
mute = '#EB8F8F',
unmute = '#A4CE8A',
},
_current_level = 0,
_mute = "no",
device = "N/A"
_mute = 'no',
device = 'N/A',
}
args = args or {}
@ -42,24 +42,27 @@ local function factory(args)
local paddings = args.paddings or 1
local ticks = args.ticks or false
local ticks_size = args.ticks_size or 7
local tick = args.tick or "|"
local tick_pre = args.tick_pre or "["
local tick_post = args.tick_post or "]"
local tick_none = args.tick_none or " "
local tick = args.tick or '|'
local tick_pre = args.tick_pre or '['
local tick_post = args.tick_post or ']'
local tick_none = args.tick_none or ' '
pulsebar.colors = args.colors or pulsebar.colors
pulsebar.followtag = args.followtag or false
pulsebar.notification_preset = args.notification_preset
pulsebar.devicetype = args.devicetype or "sink"
pulsebar.cmd = args.cmd or "pacmd list-" .. pulsebar.devicetype .. "s | sed -n -e '/*/,$!d' -e '/index/p' -e '/base volume/d' -e '/volume:/p' -e '/muted:/p' -e '/device\\.string/p'"
pulsebar.devicetype = args.devicetype or 'sink'
pulsebar.cmd = args.cmd
or 'pacmd list-'
.. pulsebar.devicetype
.. "s | sed -n -e '/*/,$!d' -e '/index/p' -e '/base volume/d' -e '/volume:/p' -e '/muted:/p' -e '/device\\.string/p'"
if not pulsebar.notification_preset then
pulsebar.notification_preset = {
font = "Monospace 10"
font = 'Monospace 10',
}
end
pulsebar.bar = wibox.widget {
pulsebar.bar = wibox.widget({
color = pulsebar.colors.unmute,
background_color = pulsebar.colors.background,
forced_height = height,
@ -69,66 +72,74 @@ local function factory(args)
ticks = ticks,
ticks_size = ticks_size,
widget = wibox.widget.progressbar,
}
})
pulsebar.tooltip = awful.tooltip({ objects = { pulsebar.bar } })
function pulsebar.update(callback)
helpers.async({ awful.util.shell, "-c", type(pulsebar.cmd) == "string" and pulsebar.cmd or pulsebar.cmd() },
helpers.async(
{ awful.util.shell, '-c', type(pulsebar.cmd) == 'string' and pulsebar.cmd or pulsebar.cmd() },
function(s)
volume_now = {
index = string.match(s, "index: (%S+)") or "N/A",
device = string.match(s, "device.string = \"(%S+)\"") or "N/A",
muted = string.match(s, "muted: (%S+)") or "N/A"
index = string.match(s, 'index: (%S+)') or 'N/A',
device = string.match(s, 'device.string = "(%S+)"') or 'N/A',
muted = string.match(s, 'muted: (%S+)') or 'N/A',
}
pulsebar.device = volume_now.index
local ch = 1
volume_now.channel = {}
for v in string.gmatch(s, ":.-(%d+)%%") do
for v in string.gmatch(s, ':.-(%d+)%%') do
volume_now.channel[ch] = v
ch = ch + 1
end
volume_now.left = volume_now.channel[1] or "N/A"
volume_now.right = volume_now.channel[2] or "N/A"
volume_now.left = volume_now.channel[1] or 'N/A'
volume_now.right = volume_now.channel[2] or 'N/A'
local volu = volume_now.left
local mute = volume_now.muted
if volu:match("N/A") or mute:match("N/A") then return end
if volu:match('N/A') or mute:match('N/A') then
return
end
if volu ~= pulsebar._current_level or mute ~= pulsebar._mute then
pulsebar._current_level = tonumber(volu)
pulsebar.bar:set_value(pulsebar._current_level / 100)
if pulsebar._current_level == 0 or mute == "yes" then
if pulsebar._current_level == 0 or mute == 'yes' then
pulsebar._mute = mute
pulsebar.tooltip:set_text ("[muted]")
pulsebar.tooltip:set_text('[muted]')
pulsebar.bar.color = pulsebar.colors.mute
pulsebar.bar.background_color = pulsebar.colors.mute_background
else
pulsebar._mute = "no"
pulsebar.tooltip:set_text(string.format("%s %s: %s", pulsebar.devicetype, pulsebar.device, volu))
pulsebar._mute = 'no'
pulsebar.tooltip:set_text(
string.format('%s %s: %s', pulsebar.devicetype, pulsebar.device, volu)
)
pulsebar.bar.color = pulsebar.colors.unmute
pulsebar.bar.background_color = pulsebar.colors.background
end
settings()
if type(callback) == "function" then callback() end
if type(callback) == 'function' then
callback()
end
end)
end
end
)
end
function pulsebar.notify()
pulsebar.update(function()
local preset = pulsebar.notification_preset
preset.title = string.format("%s %s - %s%%", pulsebar.devicetype, pulsebar.device, pulsebar._current_level)
preset.title = string.format('%s %s - %s%%', pulsebar.devicetype, pulsebar.device, pulsebar._current_level)
if pulsebar._mute == "yes" then
preset.title = preset.title .. " muted"
if pulsebar._mute == 'yes' then
preset.title = preset.title .. ' muted'
end
-- tot is the maximum number of ticks to display in the notification
@ -138,7 +149,7 @@ local function factory(args)
-- if we can grab mywibox, tot is defined as its height if
-- horizontal, or width otherwise
if wib then
if wib.position == "left" or wib.position == "right" then
if wib.position == 'left' or wib.position == 'right' then
tot = wib.width
else
tot = wib.height
@ -146,28 +157,27 @@ local function factory(args)
end
local int = math.modf((pulsebar._current_level / 100) * tot)
preset.text = string.format(
"%s%s%s%s",
tick_pre,
string.rep(tick, int),
string.rep(tick_none, tot - int),
tick_post
)
preset.text =
string.format('%s%s%s%s', tick_pre, string.rep(tick, int), string.rep(tick_none, tot - int), tick_post)
if pulsebar.followtag then preset.screen = awful.screen.focused() end
if pulsebar.followtag then
preset.screen = awful.screen.focused()
end
if not pulsebar.notification then
pulsebar.notification = naughty.notify {
pulsebar.notification = naughty.notify({
preset = preset,
destroy = function() pulsebar.notification = nil end
}
destroy = function()
pulsebar.notification = nil
end,
})
else
naughty.replace_text(pulsebar.notification, preset.title, preset.text)
end
end)
end
helpers.newtimer(string.format("pulsebar-%s-%s", pulsebar.devicetype, pulsebar.device), timeout, pulsebar.update)
helpers.newtimer(string.format('pulsebar-%s-%s', pulsebar.devicetype, pulsebar.device), timeout, pulsebar.update)
return pulsebar
end

View File

@ -6,8 +6,8 @@
--]]
local helpers = require("lain.helpers")
local wibox = require("wibox")
local helpers = require('lain.helpers')
local wibox = require('wibox')
local open, match = io.open, string.match
-- System load
@ -21,17 +21,17 @@ local function factory(args)
local settings = args.settings or function() end
function sysload.update()
local f = open("/proc/loadavg")
local ret = f:read("*all")
local f = open('/proc/loadavg')
local ret = f:read('*all')
f:close()
load_1, load_5, load_15 = match(ret, "([^%s]+) ([^%s]+) ([^%s]+)")
load_1, load_5, load_15 = match(ret, '([^%s]+) ([^%s]+) ([^%s]+)')
widget = sysload.widget
settings()
end
helpers.newtimer("sysload", timeout, sysload.update)
helpers.newtimer('sysload', timeout, sysload.update)
return sysload
end

View File

@ -5,8 +5,8 @@
--]]
local helpers = require("lain.helpers")
local wibox = require("wibox")
local helpers = require('lain.helpers')
local wibox = require('wibox')
local tonumber = tonumber
-- {thermal,core} temperature info
@ -17,15 +17,15 @@ local function factory(args)
local temp = { widget = args.widget or wibox.widget.textbox() }
local timeout = args.timeout or 30
local tempfile = args.tempfile or "/sys/devices/virtual/thermal/thermal_zone0/temp"
local format = args.format or "%.1f"
local tempfile = args.tempfile or '/sys/devices/virtual/thermal/thermal_zone0/temp'
local format = args.format or '%.1f'
local settings = args.settings or function() end
function temp.update()
helpers.async({"find", "/sys/devices", "-type", "f", "-name", "*temp*"}, function(f)
helpers.async({ 'find', '/sys/devices', '-type', 'f', '-name', '*temp*' }, function(f)
temp_now = {}
local temp_fl, temp_value
for t in f:gmatch("[^\n]+") do
for t in f:gmatch('[^\n]+') do
temp_fl = helpers.first_line(t)
if temp_fl then
temp_value = tonumber(temp_fl)
@ -35,14 +35,14 @@ local function factory(args)
if temp_now[tempfile] then
coretemp_now = string.format(format, temp_now[tempfile])
else
coretemp_now = "N/A"
coretemp_now = 'N/A'
end
widget = temp.widget
settings()
end)
end
helpers.newtimer("thermal", timeout, temp.update)
helpers.newtimer('thermal', timeout, temp.update)
return temp
end

View File

@ -5,11 +5,11 @@
--]]
local helpers = require("lain.helpers")
local json = require("lain.util").dkjson
local focused = require("awful.screen").focused
local naughty = require("naughty")
local wibox = require("wibox")
local helpers = require('lain.helpers')
local json = require('lain.util').dkjson
local focused = require('awful.screen').focused
local naughty = require('naughty')
local wibox = require('wibox')
local math = math
local os = os
local string = string
@ -26,28 +26,30 @@ local function factory(args)
local weather = { widget = args.widget or wibox.widget.textbox() }
local APPID = args.APPID -- mandatory
local timeout = args.timeout or 60 * 15 -- 15 min
local current_call = args.current_call or "curl -s 'https://api.openweathermap.org/data/2.5/weather?id=%s&units=%s&lang=%s&APPID=%s'"
local forecast_call = args.forecast_call or "curl -s 'https://api.openweathermap.org/data/2.5/forecast?id=%s&units=%s&lang=%s&APPID=%s'"
local current_call = args.current_call
or "curl -s 'https://api.openweathermap.org/data/2.5/weather?id=%s&units=%s&lang=%s&APPID=%s'"
local forecast_call = args.forecast_call
or "curl -s 'https://api.openweathermap.org/data/2.5/forecast?id=%s&units=%s&lang=%s&APPID=%s'"
local city_id = args.city_id or 0 -- placeholder
local units = args.units or "metric"
local lang = args.lang or "en"
local units = args.units or 'metric'
local lang = args.lang or 'en'
local cnt = args.cnt or 5
local icons_path = args.icons_path or helpers.icons_dir .. "openweathermap/"
local icons_path = args.icons_path or helpers.icons_dir .. 'openweathermap/'
local notification_preset = args.notification_preset or {}
local notification_text_fun = args.notification_text_fun or
function (wn)
local day = os.date("%a %d", wn["dt"])
local temp = math.floor(wn["main"]["temp"])
local desc = wn["weather"][1]["description"]
return string.format("<b>%s</b>: %s, %d ", day, desc, temp)
local notification_text_fun = args.notification_text_fun
or function(wn)
local day = os.date('%a %d', wn['dt'])
local temp = math.floor(wn['main']['temp'])
local desc = wn['weather'][1]['description']
return string.format('<b>%s</b>: %s, %d ', day, desc, temp)
end
local weather_na_markup = args.weather_na_markup or " N/A "
local weather_na_markup = args.weather_na_markup or ' N/A '
local followtag = args.followtag or false
local showpopup = args.showpopup or "on"
local showpopup = args.showpopup or 'on'
local settings = args.settings or function() end
weather.widget:set_markup(weather_na_markup)
weather.icon_path = icons_path .. "na.png"
weather.icon_path = icons_path .. 'na.png'
weather.icon = wibox.widget.imagebox(weather.icon_path)
function weather.show(seconds)
@ -62,12 +64,12 @@ local function factory(args)
weather.forecast_update()
end
weather.notification = naughty.notify {
weather.notification = naughty.notify({
preset = notification_preset,
text = weather.notification_text,
icon = weather.icon_path,
timeout = type(seconds) == "number" and seconds or notification_preset.timeout
}
timeout = type(seconds) == 'number' and seconds or notification_preset.timeout,
})
end
function weather.hide()
@ -78,10 +80,10 @@ local function factory(args)
end
function weather.attach(obj)
obj:connect_signal("mouse::enter", function()
obj:connect_signal('mouse::enter', function()
weather.show(0)
end)
obj:connect_signal("mouse::leave", function()
obj:connect_signal('mouse::leave', function()
weather.hide()
end)
end
@ -92,13 +94,13 @@ local function factory(args)
local err
weather_now, _, err = json.decode(f, 1, nil)
if not err and type(weather_now) == "table" and tonumber(weather_now["cod"]) == 200 then
weather.notification_text = ""
for i = 1, weather_now["cnt"], math.floor(weather_now["cnt"] / cnt) do
weather.notification_text = weather.notification_text ..
notification_text_fun(weather_now["list"][i])
if i < weather_now["cnt"] then
weather.notification_text = weather.notification_text .. "\n"
if not err and type(weather_now) == 'table' and tonumber(weather_now['cod']) == 200 then
weather.notification_text = ''
for i = 1, weather_now['cnt'], math.floor(weather_now['cnt'] / cnt) do
weather.notification_text = weather.notification_text
.. notification_text_fun(weather_now['list'][i])
if i < weather_now['cnt'] then
weather.notification_text = weather.notification_text .. '\n'
end
end
end
@ -111,23 +113,23 @@ local function factory(args)
local err
weather_now, _, err = json.decode(f, 1, nil)
if not err and type(weather_now) == "table" and tonumber(weather_now["cod"]) == 200 then
local sunrise = tonumber(weather_now["sys"]["sunrise"])
local sunset = tonumber(weather_now["sys"]["sunset"])
local icon = weather_now["weather"][1]["icon"]
if not err and type(weather_now) == 'table' and tonumber(weather_now['cod']) == 200 then
local sunrise = tonumber(weather_now['sys']['sunrise'])
local sunset = tonumber(weather_now['sys']['sunset'])
local icon = weather_now['weather'][1]['icon']
local loc_now = os.time()
if sunrise <= loc_now and loc_now <= sunset then
icon = string.gsub(icon, "n", "d")
icon = string.gsub(icon, 'n', 'd')
else
icon = string.gsub(icon, "d", "n")
icon = string.gsub(icon, 'd', 'n')
end
weather.icon_path = icons_path .. icon .. ".png"
weather.icon_path = icons_path .. icon .. '.png'
widget = weather.widget
settings()
else
weather.icon_path = icons_path .. "na.png"
weather.icon_path = icons_path .. 'na.png'
weather.widget:set_markup(weather_na_markup)
end
@ -135,10 +137,13 @@ local function factory(args)
end)
end
if showpopup == "on" then weather.attach(weather.widget) end
if showpopup == 'on' then
weather.attach(weather.widget)
end
weather.timer = helpers.newtimer("weather-" .. city_id, timeout, weather.update, false, true)
weather.timer_forecast = helpers.newtimer("weather_forecast-" .. city_id, timeout, weather.forecast_update, false, true)
weather.timer = helpers.newtimer('weather-' .. city_id, timeout, weather.update, false, true)
weather.timer_forecast =
helpers.newtimer('weather_forecast-' .. city_id, timeout, weather.forecast_update, false, true)
return weather
end

View File

@ -10,13 +10,29 @@ local lain = require('lain')
local awful = require('awful')
local wibox = require('wibox')
local dpi = require('beautiful.xresources').apply_dpi
local naughty = require('naughty')
local settings = (function()
local status, settings = pcall(function()
return dofile(os.getenv('HOME') .. '/.config/awesome/settings.lua')
end)
if status then
return settings
else
naughty.notify({
preset = naughty.config.presets.critical,
title = 'Error while parsing settings!',
text = settings,
})
return {}
end
end)()
local os = os
local my_table = awful.util.table or gears.table -- 4.{0,1} compatibility
local theme = {}
theme.confdir = os.getenv('HOME') .. '/.config/awesome/'
theme.wallpaper = os.getenv('HOME') .. '/.config/awesome/wall.png'
theme.wallpaper = os.getenv('HOME') .. '/.config/awesome/' .. (settings['wallpaper'] or 'wall.png')
theme.font = 'Terminus 8'
theme.menu_bg_normal = '#000000'
theme.menu_bg_focus = '#000000'
@ -146,29 +162,39 @@ local cpu = lain.widget.cpu({
end,
})
local optional = {}
-- Coretemp
--[[local tempicon = wibox.widget.imagebox(theme.widget_temp)
if settings['show_temp'] == true then
local tempicon = wibox.widget.imagebox(theme.widget_temp)
local temp = lain.widget.temp({
settings = function()
widget:set_markup(markup.fontfg(theme.font, "#f1af5f", coretemp_now .. "°C "))
-- luacheck: globals widget coretemp_now
widget:set_markup(markup.fontfg(theme.font, '#f1af5f', coretemp_now .. '°C '))
end,
})
table.insert(optional, tempicon)
table.insert(optional, temp)
end
})]]
--
-- Battery
--[[local baticon = wibox.widget.imagebox(theme.widget_batt)
if settings['show_battery'] == true then
local baticon = wibox.widget.imagebox(theme.widget_batt)
local bat = lain.widget.bat({
settings = function()
local perc = bat_now.perc ~= "N/A" and bat_now.perc .. "%" or bat_now.perc
-- luacheck: globals widget bat_now
local perc = bat_now.perc ~= 'N/A' and bat_now.perc .. '%' or bat_now.perc
if bat_now.ac_status == 1 then
perc = perc .. " plug"
perc = perc .. ' plug'
end
widget:set_markup(markup.fontfg(theme.font, theme.fg_normal, perc .. " "))
widget:set_markup(markup.fontfg(theme.font, theme.fg_normal, perc .. ' '))
end,
})
table.insert(optional, baticon)
table.insert(optional, bat)
end
})]]
--
-- ALSA volume
local volicon = wibox.widget.imagebox(theme.widget_vol)
@ -331,6 +357,7 @@ function theme.at_screen_connect(s)
},
s.mytasklist, -- Middle widget
--nil,
gears.table.join(
{ -- Right widgets
layout = wibox.layout.fixed.horizontal,
wibox.widget.systray(),
@ -360,15 +387,13 @@ function theme.at_screen_connect(s)
cpu.widget,
fsicon,
theme.fs.widget,
--weathericon,
--theme.weather.widget,
--tempicon,
--temp.widget,
--baticon,
--bat.widget,
},
optional,
{
clockicon,
mytextclock,
},
}
),
})
end

BIN
awesome/wall2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 MiB