ssiv/src/ssiv/config/__init__.py

259 lines
12 KiB
Python

# This file is part of ssiv.
#
# ssiv is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# ssiv is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with ssiv. If not, see <https://www.gnu.org/licenses/>.
from tomllib import load,loads
from .default import default
from ..co import AttrDict
__all__=[]
if not __all__:
config=AttrDict()
config|=AttrDict(
(k,AttrDict(v)) for k,v in loads(default).items())
__all__.append('config')
class InvalidConfigError(Exception):pass
def loadcustom(fp):
for k,v in load(fp).items():
try:
conf=getattr(config,k)
except AttributeError:
raise InvalidConfigError(f'unknown config key in {custom_toml!r}: {k!r}')
for ck,cv in v.items():
if ck not in conf:
raise InvalidConfigError(
f'unknown config key in {custom_toml!r}: {k}.{ck}')
conf|=AttrDict(v)
def validate(conf):
# file_reader
assert isinstance(conf.file_reader.keepalive,int),\
f'wrong type for file_reader.keepalive: {conf.file_reader.keepalive!r}'
assert conf.file_reader.keepalive>0,\
f'file_reader.keepalive should be positive: {conf.file_reader.keepalive}'
assert isinstance(conf.file_reader.recursive,bool),\
f'wrong type for file_reader.keepalive: {conf.file_reader.recursive!r}'
assert isinstance(conf.file_reader.follow,bool),\
f'wrong type for file_reader.follow: {conf.file_reader.follow!r}'
#wand_loader
assert isinstance(conf.wand_loader.procs,int),\
f'wrong type for wand_loader.procs: {wand_loader.procs!r}'
assert conf.wand_loader.procs>-1,\
f'wand_loader.procs should not be negative: {conf.wand_loader.procs}'
assert isinstance(conf.wand_loader.maxsize,int),\
f'wrong type for wand_loader.maxsize: {wand_loader.maxsize!r}'
assert conf.wand_loader.maxsize>-1,\
f'wand_loader.maxsize should not be negative: {conf.wand_loader.maxsize}'
assert isinstance(conf.wand_loader.anime,bool),\
f'wrong type for wand_loader.anime: {conf.wand_loader.anime!r}'
assert isinstance(conf.wand_loader.apng,bool),\
f'wrong type for wand_loader.apng: {conf.wand_loader.apng!r}'
# user_interface
assert isinstance(conf.user_interface.cache,int),\
f'wrong type for user_interface.cache: {user_interface.cache!r}'
assert isinstance(conf.user_interface.numsort,bool),\
f'wrong type for user_interface.numsort: {conf.user_interface.numsort!r}'
assert conf.user_interface.cache>-1,\
f'user_interface.cache should not be negative: {conf.user_interface.cache}'
assert isinstance(conf.user_interface.usepage,bool),\
f'wrong type for user_interface.usepage: {conf.user_interface.usepage!r}'
assert isinstance(conf.user_interface.double,bool),\
f'wrong type for user_interface.double: {conf.user_interface.double!r}'
assert isinstance(conf.user_interface.rtl,bool),\
f'wrong type for user_interface.rtl: {conf.user_interface.rtl!r}'
assert isinstance(conf.user_interface.antialias,bool),\
f'wrong type for user_interface.antialias: {conf.user_interface.antialias!r}'
assert isinstance(conf.user_interface.tiling,bool),\
f'wrong type for user_interface.tiling: {conf.user_interface.tiling!r}'
assert isinstance(conf.user_interface.faststep,int),\
f'wrong type for user_interface.faststep: {user_interface.faststep!r}'
assert conf.user_interface.faststep>1,\
f'user_interface.faststep should not be negative: {conf.user_interface.faststep}'
assert isinstance(conf.user_interface.screensaver,bool),\
f'wrong type for user_interface.screensaver: {conf.user_interface.screensaver!r}'
assert isinstance(conf.user_interface.startfs,bool),\
f'wrong type for user_interface.startfs: {conf.user_interface.startfs!r}'
assert isinstance(conf.user_interface.realfs,bool),\
f'wrong type for user_interface.realfs: {conf.user_interface.realfs!r}'
# thumbnail
assert isinstance(conf.thumbnail.size,int),\
f'wrong type for thumbnail.size: {conf.thumbnail.size!r}'
assert conf.thumbnail.size>0,\
f'thumbnail.size should be positive: {conf.thumbnail.size}'
assert isinstance(conf.thumbnail.maxsize,int),\
f'wrong type for thumbnail.maxsize: {conf.thumbnail.maxsize!r}'
assert conf.thumbnail.maxsize>0,\
f'thumbnail.maxsize should be positive: {conf.thumbnail.maxsize}'
assert isinstance(conf.thumbnail.gap,int),\
f'wrong type for thumbnail.gap: {conf.thumbnail.gap!r}'
assert conf.thumbnail.gap>0,\
f'thumbnail.gap should be positive: {conf.thumbnail.gap}'
# style
assert isinstance(conf.style.bgcolor,list) and len(conf.style.bgcolor)==3 and \
all(isinstance(c,int) and -1<c<256 for c in conf.style.bgcolor),\
f'style.bgcolor should be a list of three integer in 0-255: {conf.style.bgcolor}'
assert isinstance(conf.style.fgcolor,list) and len(conf.style.fgcolor)==3 and \
all(isinstance(c,int) and -1<c<256 for c in conf.style.fgcolor),\
f'style.fgcolor should be a list of three integer in 0-255: {conf.style.fgcolor}'
assert isinstance(conf.style.size,list) and len(conf.style.size)==2 and \
all(isinstance(c,int) and c>1 for c in conf.style.size),\
f'style.bgcolor should be a list of two positive integer: {conf.style.size}'
assert isinstance(conf.style.checker,bool),\
f'wrong type for style.checker: {conf.style.checker!r}'
assert isinstance(conf.style.decoration,bool),\
f'wrong type for style.decoration: {conf.style.decoration!r}'
# statusbar
assert isinstance(conf.statusbar.size,int),\
f'wrong type for statusbar.size: {conf.statusbar.size!r}'
assert conf.thumbnail.size==0 or conf.thumbnail.size>11,\
f'thumbnail.size should be 0 or at least 12: {conf.thumbnail.size}'
assert conf.statusbar.posland in ('top','bottom','left','right'),\
f'wrong value for statusbar.posland: {conf.statusbar.posland!r}'
assert conf.statusbar.posport in ('top','bottom','left','right'),\
f'wrong value for statusbar.posport: {conf.statusbar.posport!r}'
# motionbar
assert isinstance(conf.motionbar.size,int),\
f'wrong type for motionbar.size: {conf.motionbar.size!r}'
assert conf.thumbnail.size>11,\
f'thumbnail.size should be at least 12: {conf.thumbnail.size}'
assert conf.motionbar.posxaxis in ('top','bottom','disabled'),\
f'wrong value for motionbar.posxaxis: {conf.motionbar.posxaxis!r}'
assert conf.motionbar.posyaxis in ('left','right','disabled'),\
f'wrong value for motionbar.posyaxis: {conf.motionbar.posyaxis!r}'
# renderer
if not isinstance(conf.renderer.driver,str):
assert conf.renderer.driver in (False,0),\
f'wrong value for renderer.driver: {conf.renderer.driver!r}'
assert isinstance(conf.renderer.vsync,bool),\
f'wrong type for renderer.vsync: {conf.renderer.vsync!r}'
assert isinstance(conf.renderer.prime,bool),\
f'wrong type for renderer.prime: {conf.renderer.prime!r}'
# log
assert isinstance(conf.log.level,int),\
f'wrong type for log.level: {conf.log.level!r}'
assert conf.log.level>-1,\
f'log.level should not be negative: {conf.log.level}'
assert isinstance(conf.log.devel,bool),\
f'wrong type for log.devel: {conf.log.devel!r}'
if not isinstance(conf.log.stdout,str):
assert conf.log.stdout is not False,\
f'wrong value for log.stdout: {conf.log.stdout!r}'
if not isinstance(conf.log.stderr,str):
assert conf.log.stderr is not False,\
f'wrong value for log.stderr: {conf.log.stderr!r}'
assert conf.log.color in ('always','never','auto'),\
f'wrong value for log.color: {conf.log.color!r}'
# environ
for option in conf.environ:
assert isinstance(conf.environ[option],list),\
f'wrong value for conf.environ.{option}: {conf.environ[option]!r}'
if conf.environ[option]:
for item in conf.environ[option]:
assert isinstance(item,list) and len(item)==2 and \
all(isinstance(s,str) for s in item),\
f'wrong value in conf.environ.{option}: {item!r}'
# control
kbd=dict(
kbd_global=set(),
kbd_tiling=set(),
kbd_canvas=set(),
kbd_motion=set(),
wheel_mask=set()
)
for key in kbd:
for action in conf[key]:
assert isinstance(conf[key][action],list),\
f'wrong value for {key}.{action}: {conf[key][action]!r}'
for keys in conf[key][action]:
assert isinstance(keys,list) and \
all(isinstance(s,str) for s in keys),\
f'wrong value for {key}.{action}: {keys!r}'
assert frozenset(keys) not in kbd[key],\
f'duplicate bindings for {key}.{action}: {keys}'
if keys:
kbd[key].add(frozenset(keys))
for action in conf.kbd_motion:
for keys in conf.kbd_motion[action]:
assert frozenset(keys) not in kbd['kbd_canvas'],\
f'duplicate bindings for kbd_motion.{action}: {keys}'
btns=set()
for action in conf.mouse_clck:
assert isinstance(conf.mouse_clck[action],list) and \
all(isinstance(s,str) for s in conf.mouse_clck[action]),\
f'wrong value for mouse_clck.{action}: {conf.mouse_clck[action]!r}'
assert frozenset(conf.mouse_clck[action]) not in btns,\
f'duplicate binding for mouse_clck.{action}: {conf.mouse_clck[action]}'
if conf.mouse_clck[action]:
btns.add(frozenset(conf.mouse_clck[action]))
kbd['mouse_mask']=set()
del kbd['wheel_mask']
mskbtns=set()
for action in conf.mouse_mask:
assert isinstance(conf.mouse_mask[action],list),\
f'wrong value for mouse_mask.{action}: {conf.mouse_mask[action]!r}'
for binding in conf.mouse_mask[action]:
assert isinstance(binding,list),\
f'wrong value for mouse_mask.{action}: {binding!r}'
keys=frozenset(s for s in binding
if isinstance(s,str) and s.startswith('SDLK_'))
btn=frozenset(binding)-keys
for ks in kbd.values():
assert keys not in ks,\
f'duplicate keys for mouse_mask.{action}: {binding}'
if keys:
kbd['mouse_mask'].add(keys)
assert btn not in mskbtns,\
f'duplicate button for mouse_mask.{action}: {binding}'
if btn:
mskbtns.add(btn)
assert isinstance(conf.mouse_dire.revxmtn,bool),\
f'wrong type for mouse_dire.revxmtn: {conf.mouse_dire.revxmtn!r}'
assert isinstance(conf.mouse_dire.revymtn,bool),\
f'wrong type for mouse_dire.revymtn: {conf.mouse_dire.revymtn!r}'
assert isinstance(conf.mouse_dire.revxwhl,bool),\
f'wrong type for mouse_dire.revxwhl: {conf.mouse_dire.revxwhl!r}'
assert isinstance(conf.mouse_dire.revywhl,bool),\
f'wrong type for mouse_dire.revywhl: {conf.mouse_dire.revywhl!r}'
return True
__all__.extend(('loadcustom','validate','default'))
# Local Variables:
# coding: utf-8
# mode: python
# python-indent-offset: 4
# indent-tabs-mode: nil
# End: