summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fb.119
-rwxr-xr-xfb.py62
2 files changed, 75 insertions, 6 deletions
diff --git a/fb.1 b/fb.1
index c777c5d..87af4b2 100644
--- a/fb.1
+++ b/fb.1
@@ -128,7 +128,24 @@ The following option names are supported:
.It pastebin
The URL of the pastebin you want to use
.It clipboard_cmd
-The command used to copy URLs of uploaded files to the clipboard. This defaults to pbcopy on Darwin and xclip otherwise.
+The command used to copy URLs of uploaded files to the clipboard.
+This defaults to
+.Xr xclip 1 on X11,
+.Xr wl-copy 1 on Wayland and
+.Xr pbcopy 1 on Mac OS / Darwin.
+.It clipboard_target
+Configure which clipboard to use. Allowed settings:
+.Bl -tag -width "none / off"
+.It default
+Use the default behavior, i.e. "primary" for X11/xclip and "clipboard" for Wayland/wl-copy.
+This is implicitly the default if not specified.
+.It none / off
+Disable copying the upload URL into the clipboard.
+.It primary
+Enforce copy into the "primary" selection (for Wayland/wl-copy).
+.It clipboard
+Enforce copy into the "clipboard" selection (for X11/xclip).
+.El
.It apikey_file
The file that contains the API key. This defaults to "$XDG_CONFIG_HOME/fb-client/apikey"
.El
diff --git a/fb.py b/fb.py
index 15d92d2..cda7b32 100755
--- a/fb.py
+++ b/fb.py
@@ -21,10 +21,17 @@ import sys
import tarfile
import tempfile
import time
+import typing
import xdg.BaseDirectory
from io import BytesIO
+
+X11_CLIPBOARD_CMD = 'xclip'
+WAYLAND_CLIPBOARD_CMD = 'wl-copy'
+DARWIN_CLIPBOARD_CMD = 'pbcopy'
+
+
class ApikeyNotFoundException(Exception):
pass
@@ -394,21 +401,55 @@ class Compressor:
f_out.writelines(f_in)
return dst
+
+class ConfigConstraint():
+ def __init__(self, cvar: str, match: str, pattern: typing.Any, enforce: bool = False):
+ self.cvar: str = cvar
+ self.match: str = match.lower()
+ self.pattern: typing.Any = pattern
+ self.enforce: bool = enforce
+
+ def validate(self, input: str) -> bool:
+ result = False
+ if self.match == 'enum' and (isinstance(self.pattern, tuple) or
+ isinstance(self.pattern, list)):
+ result = input in self.pattern
+ if self.enforce:
+ print(f"Invalid config setting for {self.cvar}: '{input}', " \
+ "allowed: '{self.pattern}' ({self.match})", file=sys.stderr)
+ raise ValueError(f'Invalid {self.cvar} config setting: {input}')
+ return result
+
+
class ConfigParser:
+
+ MATCHER = re.compile('^(?P<key>[^=]+)=(?P<quotechar>"?)(?P<value>.+)(?P=quotechar)$')
+
+ CONSTRAINTS = {
+ 'clipboard_target': ConfigConstraint('clipboard_target', 'enum', ('none', 'off', 'default', 'primary', 'clipboard'))
+ }
+
def __init__(self, file, ignoreMissing=False):
self.config = {}
self.config["pastebin"] = "https://paste.xinu.at"
- self.config["clipboard_cmd"] = "xclip"
+ self.config["clipboard_cmd"] = X11_CLIPBOARD_CMD
if os.uname()[0] == "Darwin":
- self.config["clipboard_cmd"] = "pbcopy"
+ self.config["clipboard_cmd"] = DARWIN_CLIPBOARD_CMD
elif os.environ.get('XDG_SESSION_TYPE') == 'wayland':
- self.config["clipboard_cmd"] = "wl-copy"
+ self.config["clipboard_cmd"] = WAYLAND_CLIPBOARD_CMD
self.config["apikey_file"] = os.path.join(xdg.BaseDirectory.xdg_config_home, "fb-client/apikey")
self._parse(file, ignoreMissing=ignoreMissing)
+ self._validate()
self.config["apikey_file"] = os.path.expandvars(self.config["apikey_file"])
+ def _validate(self):
+ for cvar, constraint in self.CONSTRAINTS.items():
+ if not constraint.validate(self.config[cvar]):
+ print(f"WARN: ignoring invalid config setting: '{cvar}'", file=sys.stderr)
+ del self.config[cvar]
+
def _parse(self, file, ignoreMissing=False):
try:
fh = open(file)
@@ -420,7 +461,7 @@ class ConfigParser:
with fh:
for line in fh:
- matches = re.match('^(?P<key>[^=]+)=(?P<quotechar>"?)(?P<value>.+)(?P=quotechar)$', line)
+ matches = self.MATCHER.match(line)
if matches != None:
self.config[matches.group('key')] = matches.group('value')
@@ -645,9 +686,20 @@ class FBClient:
self.setClipboard(' '.join(urls))
def setClipboard(self, content):
+ cmd = self.config['clipboard_cmd']
+ args = []
+ target = self.config.get('clipboard_target')
+ if target in ('none', 'off'):
+ return
+ elif target == 'primary':
+ if cmd == WAYLAND_CLIPBOARD_CMD:
+ args.extend(['--primary'])
+ elif target == 'clipboard':
+ if cmd == X11_CLIPBOARD_CMD:
+ args.extend(['-selection', 'clipboard'])
try:
with open('/dev/null', 'w') as devnull:
- p = subprocess.Popen([self.config['clipboard_cmd']], stdin=subprocess.PIPE, stdout=devnull, stderr=devnull)
+ p = subprocess.Popen([cmd, *args], stdin=subprocess.PIPE, stdout=devnull, stderr=devnull)
p.communicate(input=content.encode('utf-8'))
except OSError as e:
if e.errno == errno.ENOENT: