aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2023-10-30 10:23:49 +0100
committerdec05eba <dec05eba@protonmail.com>2023-10-30 10:37:58 +0100
commitf2bbfe83b4b23e87d8a049a2d698c6576a5bcd8c (patch)
tree0734cabcfe51036a011e46cd83ae7ac15c5dfa95
Initial commit
-rw-r--r--LICENSE19
-rw-r--r--README.md32
-rwxr-xr-xpython/qm-file-manager.py31
-rwxr-xr-xshell/qm-file-manager.sh32
-rw-r--r--zig/qm-file-manager.zig54
5 files changed, 168 insertions, 0 deletions
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..00bd50b
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2023 dec05eba
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..5120e91
--- /dev/null
+++ b/README.md
@@ -0,0 +1,32 @@
+qm plugin protocol with example. A "file manager" plugin example is written in shell script, python and zig
+
+# Protocol
+## Input
+Plugins get inputs as environment variables.\
+The environment variable `ACTION` is set to `get` to get data.\
+The environment variable `URL` is set to _url_ relevant to the page, so for example for a file manager `URL` is set to the directory to display files of.
+## Output
+Plugins output data by writing lines to stdout.\
+Data is first written to stdout and then a _command_ is written to stdout.\
+First `add_tab` command is expected, followed by multiple `add_body_item`. The body items are put in the tab that is output before the body items.
+### add_tab
+The add_tab command expects `title` data, for example:
+```bash
+echo "title Files"
+echo "add_tab"
+```
+### add_body_item
+The add_body_item command expects `title` and `url` data and optionally `thumbnail_url` and `thumbnail_size`, for example:
+```bash
+echo "title file.png"
+echo "url img1.png"
+echo "thumbnail_url img1.png"
+echo "thumbnail_size 1920x1080"
+echo "add_body_item"
+
+echo "title img2.png"
+echo "url img2.png"
+echo "thumbnail_url img2.png"
+echo "thumbnail_size 1280x720"
+echo "add_body_item"
+```
diff --git a/python/qm-file-manager.py b/python/qm-file-manager.py
new file mode 100755
index 0000000..c022d3e
--- /dev/null
+++ b/python/qm-file-manager.py
@@ -0,0 +1,31 @@
+#!/usr/bin/env python3
+
+import os
+
+def get(url):
+ print("title %s" % url)
+ print("add_tab")
+
+ if url != "/":
+ print("title Go to parent directory")
+ print("url ..")
+ print("thumbnail_url folder.png")
+ print("thumbnail_size 32x32")
+ print("add_body_item")
+
+ for entry in os.scandir(url):
+ print("title %s" % entry.path)
+ print("url %s" % entry.path)
+ if entry.is_dir():
+ print("thumbnail_url folder.png")
+ else:
+ print("thumbnail_url file.png")
+ print("thumbnail_size 32x32")
+ print("add_body_item")
+
+action = os.environ["ACTION"]
+if action == "get":
+ get(os.environ["URL"])
+else:
+ print("error unexpected action %s" % action)
+ exit(1) \ No newline at end of file
diff --git a/shell/qm-file-manager.sh b/shell/qm-file-manager.sh
new file mode 100755
index 0000000..c5e6474
--- /dev/null
+++ b/shell/qm-file-manager.sh
@@ -0,0 +1,32 @@
+#!/bin/sh
+
+get() {
+ echo "title $1"
+ echo "add_tab"
+
+ if [ "$1" != "/" ]; then
+ echo "title Go to parent directory"
+ echo "url .."
+ echo "thumbnail_url folder.png"
+ echo "thumbnail_size 32x32"
+ echo "add_body_item"
+ fi
+
+ for f in "$1/"*; do
+ echo "title $f"
+ echo "url $f"
+ if [ -d "$f" ]; then
+ echo "thumbnail_url folder.png"
+ else
+ echo "thumbnail_url file.png"
+ fi
+ echo "thumbnail_size 32x32"
+ echo "add_body_item"
+ done
+}
+
+case "$ACTION" in
+ "get") get "$URL";;
+ *) echo "error unexpected action $ACTION"; exit 1;;
+esac
+
diff --git a/zig/qm-file-manager.zig b/zig/qm-file-manager.zig
new file mode 100644
index 0000000..b8b06e5
--- /dev/null
+++ b/zig/qm-file-manager.zig
@@ -0,0 +1,54 @@
+const std = @import("std");
+
+const stdout_file = std.io.getStdOut().writer();
+var bw = std.io.bufferedWriter(stdout_file);
+const stdout = bw.writer();
+
+pub fn main() !u8 {
+ const action = std.os.getenv("ACTION") orelse return error.MissingAction;
+ if (std.mem.eql(u8, action, "get")) {
+ try get(std.os.getenv("URL") orelse return error.MissingUrl);
+ return 0;
+ } else {
+ try stdout.print("error unexpected action {s}\n", .{action});
+ try bw.flush();
+ return 1;
+ }
+}
+
+fn get(url: []const u8) !void {
+ try stdout.print("title {s}\n", .{url});
+ try stdout.print("add_tab\n", .{});
+
+ if (!std.mem.eql(u8, url, "/")) {
+ try stdout.print("title Go to parent directory\n", .{});
+ try stdout.print("url ..\n", .{});
+ try stdout.print("thumbnail_url folder.png\n", .{});
+ try stdout.print("thumbnail_size 32x32\n", .{});
+ try stdout.print("add_body_item\n", .{});
+ }
+
+ var dirIt = try std.fs.cwd().openIterableDir(url, .{ .no_follow = true });
+ defer dirIt.close();
+
+ var pathBuf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
+
+ var it = dirIt.iterate();
+ while (try it.next()) |*entry| {
+ var fba = std.heap.FixedBufferAllocator.init(&pathBuf);
+ var allocator = fba.allocator();
+ const fullFilepath = try std.fs.path.join(allocator, &[_][]const u8{ url, entry.name });
+
+ try stdout.print("title {s}\n", .{fullFilepath});
+ try stdout.print("url {s}\n", .{fullFilepath});
+ if (entry.kind == .directory) {
+ try stdout.print("thumbnail_url folder.png\n", .{});
+ } else {
+ try stdout.print("thumbnail_url file.png\n", .{});
+ }
+ try stdout.print("thumbnail_size 32x32\n", .{});
+ try stdout.print("add_body_item\n", .{});
+ }
+
+ try bw.flush();
+}