cortav  Diff

Differences From Artifact [4b787982a7]:

To Artifact [550cdedbd6]:


1
2

3
4
5
6
7
8
9
..
43
44
45
46
47
48
49




50
51
52
53
54
55
56
...
546
547
548
549
550
551
552

553
554
555
556
557
558
559
...
587
588
589
590
591
592
593








594
595
596
597
598
599
600
...
885
886
887
888
889
890
891




892
893
894
895
896
897
898
...
935
936
937
938
939
940
941


























































































































































-- [ʞ] sirsem.lua
--  ~ lexu hale <lexi@hale.su>

--  ? utility library with functionality common to
--    cortav.lua and its extensions
--    from Ranuir "software utility"
--  > local ss = require 'sirsem.lua'

local ss
do -- pull ourselves up by our own bootstraps
................................................................................
	local new = {}
	for k, v in pairs(list) do
		local nk,nv = fn(k,v)
		new[nk or k] = nv or v
	end
	return new
end





function ss.kfilter(list, fn)
	local new = {}
	for k, v in pairs(list) do
		if fn(k,v) then new[k] = v end
	end
	return new
................................................................................

function ss.declare(c)
	local cls = setmetatable({
		__name = c.ident;
	}, {
		__name = 'class';
		__tostring = function() return c.ident or '(class)' end;

	})

	cls.__call = c.call
	cls.__index = function(self, k)
		if c.default and c.default[k] then
			return c.default[k]
		end
................................................................................
		if c.cast.string then
			cls.__tostring = c.cast.string
		end
		if c.cast.number then
			cls.__tonumber = c.cast.number
		end
	end









	cls.mk = function(...)
		local val = setmetatable(c.mk and c.mk(...) or {}, cls)
		if c.init then
			for k,v in pairs(c.init) do
				val[k] = v
			end
................................................................................
				end
			else
				me:react(sym)
			end
		end;
	};
}





-- convenience buffer for holding strings under
-- construction, accumulating and compiling then in
-- as quick a way as lua permits
ss.strac = ss.declare {
	ident = 'string-accumulator';
	mk = function() return {
................................................................................
		end;
		wrap = function(self,a,b)
			table.insert(self.strs, 1, a)
			table.insert(self.strs, b)
		end;
	};
}



























































































































































|
>







 







>
>
>
>







 







>







 







>
>
>
>
>
>
>
>







 







>
>
>
>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
..
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
...
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
...
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
...
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
...
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
-- [ʞ] sirsem.lua
--  ~ lexi hale <lexi@hale.su>
--    glowpelt (hsl conversion)
--  ? utility library with functionality common to
--    cortav.lua and its extensions
--    from Ranuir "software utility"
--  > local ss = require 'sirsem.lua'

local ss
do -- pull ourselves up by our own bootstraps
................................................................................
	local new = {}
	for k, v in pairs(list) do
		local nk,nv = fn(k,v)
		new[nk or k] = nv or v
	end
	return new
end
function ss.tmap(fn, a, ...)
	if a == nil then return end
	return fn(a), ss.tmap(fn, ...)
end

function ss.kfilter(list, fn)
	local new = {}
	for k, v in pairs(list) do
		if fn(k,v) then new[k] = v end
	end
	return new
................................................................................

function ss.declare(c)
	local cls = setmetatable({
		__name = c.ident;
	}, {
		__name = 'class';
		__tostring = function() return c.ident or '(class)' end;
	   __index = c.cfns;
	})

	cls.__call = c.call
	cls.__index = function(self, k)
		if c.default and c.default[k] then
			return c.default[k]
		end
................................................................................
		if c.cast.string then
			cls.__tostring = c.cast.string
		end
		if c.cast.number then
			cls.__tonumber = c.cast.number
		end
	end

	if c.op then
		cls.__add = c.op.sum
		cls.__sub = c.op.sub
		cls.__div = c.op.div
		cls.__mul = c.op.mul
		cls.__concat = c.op.cat
	end

	cls.mk = function(...)
		local val = setmetatable(c.mk and c.mk(...) or {}, cls)
		if c.init then
			for k,v in pairs(c.init) do
				val[k] = v
			end
................................................................................
				end
			else
				me:react(sym)
			end
		end;
	};
}

function ss.math.clamp(v, l, h)
	return math.max(math.min(v, h or 1), l or 0)
end

-- convenience buffer for holding strings under
-- construction, accumulating and compiling then in
-- as quick a way as lua permits
ss.strac = ss.declare {
	ident = 'string-accumulator';
	mk = function() return {
................................................................................
		end;
		wrap = function(self,a,b)
			table.insert(self.strs, 1, a)
			table.insert(self.strs, b)
		end;
	};
}

-- color class based on c.hale.su/sorcery's, hsl conversion
-- code written by glowpelt. TODO switch to LCH
local function clip(v, ...)
	if v == nil then return end
	return math.max(0,math.min(0xFF,math.floor(v))), clip(...)
end;
local function bytefrac(f, ...)
	if f == nil then return end
	return clip(f*0xFF), bytefrac(...)
end
ss.color = ss.declare {
	ident = 'color';
	mk = function(h,s,l,a) return {
		hue = h or 0.0;
		sat = s or 0.0;
		lum = l or 0.0;
		alpha = a or 1.0;
	} end;
	cfns = {
		byteclip = clip;
		bytefrac = bytefrac;
	};
	cast = {
		string = function(self) return self:hex() end;
		number = function(self) return self:u32() end;
	};
	op = {
		sum = function(self, other)
			if ss.color.is(other) then
				local fac = ss.math.lerp(self.alpha, 1, other.alpha)
				return self:blend(other, fac):warp(function(c)
					c.alpha = ss.math.clamp(self.alpha+other.alpha)
				end)
			else -- color + number = brighter color
				return self:warp(function(c)
					c.lum = c.lum + other
				end)
			end
		end;
		mul = function(self, other)
			if ss.color.is(other) then
				ss.color.exn 'how the heck do you multiply in hsl anyway':throw()
			else
				return self:warp(function(c)
					c.lum = c.lum * other
				end)
			end
		end;
	};
	fns = {
		tuple = function(self)
			return self.hue, self.sat, self.lum, self.alpha
		end;
		warp = function(self, func)
			local n = self:clone()
			func(n)
			return n
		end;
		blend = function(self, other, fac)
			return ss.color(
				ss.math.lerp(fac, self.hue, other.hue),
				ss.math.lerp(fac, self.sat, other.sat),
				ss.math.lerp(fac, self.lum, other.lum),
				ss.math.lerp(fac, self.alpha, other.alpha))
		end;
		hex = function(self)
			local r,g,b,a = bytefrac(self:rgb_t())
			if self.alpha == 1 then a = nil end
			return string.format('#'..string.rep('%02x',a and 4 or 3),
				r,g,b,a)
		end;
		u32 = function(self)
			local r,g,b,a = bytefrac(self:rgb_t())
			return r<<24 | g << 16 | b << 8 | a
		end;
		bytes = function(self)
			return { bytefrac(self:rgb_t()) }
		end;
		alt = function(self, fld, new)
			if self[fld] then
				return self:warp(function(c) c[fld]=new end)
			else
				ss.color.exn('no such field %s in color', fld):throw()
			end
		end;
		rgb = function(self)
			-- convenience function to get a standardized struct
			local r,g,b,a = self:rgb_t()
			return {
				red = r;
				green = g;
				blue = b;
				alpha = a;
			}
		end;
		rgb_t = function(self)
			-- returns rgba values as a tuple
			local value = function(n1, n2, hue)
				if hue > 360 then
					hue = hue - 360
				elseif hue < 0 then
					hue = hue + 360
				end
				if hue < 60 then
					return n1 + (n2 - n1) * hue/60
				elseif hue < 180 then
					return n2
				elseif hue < 240 then
					return n1 + (n2 - n1) * (240 - hue)/60
				else
					return n1
				end
			end
			local h,s,l,alpha = self:tuple()
			local m2
			if l < 0.5 then
				m2 = l * (1 + s)
			else
				m2 = l + s - l * s
			end
			local m1 = 2 * l - m2
			if s == 0 then
				-- Achromatic, there is no hue
				-- In book this errors if hue is not undefined, but we set hue to 0 in this case, not nil or something, so
				return l, l, l, alpha
			else
				-- Chromatic case, so there is a hue
				return
					value(m1, m2, h + 120),
					value(m1, m2, h),
					value(m1, m2, h - 120),
					alpha
			end
		end;
	};
};
ss.color.exn = ss.exnkind 'color error'

ss.cmdfmt = function(cmd, ...)
	return string.format(cmd, ss.tmap(function(s)
		if typeof(s) == 'string' then
			return string.format("%q", s)
			-- FIXME this is incredibly lazy and uses lua quoting, not
			-- bourne shell quoting. it *will* cause problems if anything
			-- exotic finds its way in and needs to be fixed.
			-- TODO provide a proper popen in the C wrapper so wrapped
			-- versions at least can launch programs in a sane and secure
			-- way.
		else
			return s
		end
	end, ...))
end