1
0
Fork 0
This commit is contained in:
Arthur K. 2025-06-16 11:04:16 +03:00
parent ce19d6a62c
commit 624ab42f73
Signed by: wzray
GPG key ID: B97F30FDC4636357
26 changed files with 493 additions and 163 deletions

View file

@ -1,39 +1,146 @@
#!/usr/bin/env python3
import json
import os
import subprocess
import sys
from typing import Literal
import requests
import time
import threading
import time
from concurrent.futures import ThreadPoolExecutor
from typing import Literal
import requests
state: Literal["loading", "done", "fail"] = "loading"
def die(r: str):
print(r, file=sys.stderr)
exit(1)
def strip_equal(msg: str, substring: str, n_max: int) -> str:
if n_max <= 0 or msg[0] != substring or msg[-1] != substring:
return msg
return strip_equal(msg[1:-1], substring, n_max - 1)
def cleanup_string(s: str) -> str:
return strip_equal(s.replace('\n','').strip(), '`', 4)
with open(f"{os.environ['HOME']}/.secrets/openrouter.nike.secret") as f:
KEY=f.readline().strip()
if not KEY:
die("Missing key!")
HEADERS = {'Authorization': f'Bearer {KEY}'}
def spin(text: str):
interval = 80
spinner = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]
i = 0
while state == "loading":
i = (i + 1) % len(spinner)
print(f"\r{spinner[i]} {text}", end=' ')
time.sleep(interval / 1000)
symbol = "✔️" if state == "done" else "❌"
print(f"\r{symbol} {text}")
with subprocess.Popen(["git", "diff", "--staged"], stdout=subprocess.PIPE) as ps:
ps.wait()
DIFF = ps.stdout and ps.stdout.read().decode('utf-8').strip()
if not DIFF or DIFF == "":
die("Nothing to commit!")
URL = 'http://higpu:11434/api/chat'
MODEL = 'gemma3:4b'
SAMPLES = [
{
"role": "user",
"content": "\ndiff --git a/meson.build b/meson.build\nindex 5ee43f7..bae848d 100644\n--- a/meson.build\n+++ b/meson.build\n@@ -1,5 +1,5 @@\n project('ukb', 'c',\n- version: '0.1.0',\n+ version: '0.2.1',\n default_options: ['warning_level=2', 'optimization=2'],\n )"
},
{
"role": "assistant",
"content": "chore: bump version to `0.2.1`"
},
{
"role": "user",
"content": "\ndiff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml\nindex fa4f919..9fadc0d 100644\n--- a/.github/workflows/workflow.yml\n+++ b/.github/workflows/workflow.yml\n@@ -19,7 +19,7 @@ jobs:\n libjson-c-dev libx11-dev \\\n zip\n \n- - name: Build (Linux)\n+ - name: Build (`linux-x86_64`)\n run: |\n meson setup build.linux \\\n --prefix=/ \\\n@@ -29,7 +29,7 @@ jobs:\n meson compile -C build.linux\n meson install -C build.linux --destdir=install\n \n- - name: Build (Windows)\n+ - name: Build (`windows-x86_64`)\n run: |\n cat > mingw-cross.txt <<EOF\n [binaries]\n@@ -59,16 +59,17 @@ jobs:\n \n - name: Package artifacts\n env:\n- ARTIFACT_SUFFIX: ${{ startsWith(github.ref, 'refs/tags/v') && format('-{0}', github.ref_name) || '' }}\n+ VERSION_SUFFIX: ${{ startsWith(github.ref, 'refs/tags/v') && format('-{0}', github.ref_name) || '' }}\n run: |\n mkdir artifacts\n+ BASE=\"ukb$VERSION_SUFFIX\"\n \n- NAME=\"ukb-linux$ARTIFACT_SUFFIX\"\n+ NAME=\"$BASE-linux-x86_64\"\n cd build.linux/install\n tar czf \"../../artifacts/$NAME.tar.gz\" *\n cd ../..\n \n- NAME=\"ukb-windows$ARTIFACT_SUFFIX\"\n+ NAME=\"$BASE-windows-x86_64\"\n cd build.win/install\n zip -r \"../../artifacts/$NAME.zip\" *\n cd ../.."
},
{
"role": "assistant",
"content": "feat: include arch in artifacts names"
},
{
"role": "user",
"content": "\ndiff --git a/src/main.c b/src/main.c\nindex 2d87a78..0f64564 100644\n--- a/src/main.c\n+++ b/src/main.c\n@@ -11,6 +11,7 @@\n \n static struct {\n bool silent;\n+ bool list;\n const char* backend;\n } args;\n \n@@ -20,6 +21,7 @@ static const char* usage =\n \" -h show this help page\\n\"\n \" -s be silent and don't print anything to stderr\\n\"\n \" -b manually specify backend that should be used\\n\"\n+ \" -l list all registered backends and their availability\\n\"\n \" it will be used even if it is reported as unavailable\\n\"\n \"\";\n \n@@ -28,9 +30,10 @@ void parse_args(int argc, char **argv) {\n int opt;\n \n args.silent = false;\n+ args.list = false;\n args.backend = NULL;\n \n- while ((opt = getopt(argc, argv, \"shb:\")) != -1) {\n+ while ((opt = getopt(argc, argv, \"shb:l\")) != -1) {\n switch (opt) {\n case 's':\n args.silent = true;\n@@ -40,6 +43,10 @@ void parse_args(int argc, char **argv) {\n args.backend = optarg;\n break;\n \n+ case 'l':\n+ args.list = true;\n+ break;\n+\n case '?':\n fatal(\"Invalid option or missing argument\");\n break;\n@@ -54,6 +61,22 @@ void parse_args(int argc, char **argv) {\n }\n \n \n+void list_backends() {\n+ printf(\"Registered backends:\\n\\n\");\n+\n+ for (size_t i = 0; i < ukb_backends_number; ++i) {\n+ const ukb_backend_t *b = ukb_backends[i];\n+ if (ukb_backend_can_use(b)) {\n+ printf(\" * %s [available]\\n\", ukb_backend_name(b));\n+ } else {\n+ printf(\" * %s\\n\", ukb_backend_name(b));\n+ }\n+ }\n+\n+ printf(\"\\n\");\n+}\n+\n+\n void cb_print(const char* layout) {\n printf(\"%s\\n\", layout);\n fflush(stdout);\n@@ -62,6 +85,11 @@ void cb_print(const char* layout) {\n int main(int argc, char **argv) {\n parse_args(argc, argv);\n \n+ if (args.list) {\n+ list_backends();\n+ return 0;\n+ }\n+\n const ukb_backend_t *b;\n \n if (args.backend) {"
},
{
"role": "assistant",
"content": "feat: add list (`-l`) option to ukb"
},
{
"role": "user",
"content": "\ndiff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml\nindex 4a6e5bc..fa4f919 100644\n--- a/.github/workflows/workflow.yml\n+++ b/.github/workflows/workflow.yml\n@@ -21,7 +21,11 @@ jobs:\n \n - name: Build (Linux)\n run: |\n- meson setup build.linux\n+ meson setup build.linux \\\n+ --prefix=/ \\\n+ --libdir=/lib \\\n+ --buildtype=release \\\n+ --strip\n meson compile -C build.linux\n meson install -C build.linux --destdir=install\n \n@@ -33,7 +37,7 @@ jobs:\n cpp = 'x86_64-w64-mingw32-g++'\n ar = 'x86_64-w64-mingw32-ar'\n strip = 'x86_64-w64-mingw32-strip'\n- pkgconfig = 'x86_64-w64-mingw32-pkg-config'\n+ pkg-config = 'x86_64-w64-mingw32-pkg-config'\n exe_wrapper = ''\n \n [host_machine]\n@@ -46,7 +50,10 @@ jobs:\n prefix = '/'\n EOF\n \n- meson setup build.win --cross-file mingw-cross.txt\n+ meson setup build.win \\\n+ --cross-file mingw-cross.txt \\\n+ --buildtype=release \\\n+ --strip\n meson compile -C build.win\n meson install -C build.win --destdir=install\n \ndiff --git a/meson.build b/meson.build\nindex 898c3e0..5ee43f7 100644\n--- a/meson.build\n+++ b/meson.build\n@@ -30,18 +30,17 @@ endif\n \n install_headers('include/ukb.h', subdir: 'ukb')\n \n-libukb_kwargs = {\n- 'include_directories': inc,\n- 'dependencies': deps,\n- 'c_args': ['-DUKB_BACKENDS_INTERNAL'],\n- 'install': true,\n-}\n-libukb_a = static_library('ukb', lib_src, kwargs: libukb_kwargs)\n-libukb_so = shared_library('ukb', lib_src, kwargs: libukb_kwargs)\n+libukb = both_libraries('ukb', lib_src,\n+ include_directories: inc,\n+ dependencies: deps,\n+ c_args: ['-DUKB_BACKENDS_INTERNAL'],\n+ install: true,\n+ install_dir: get_option('libdir'),\n+)\n \n \n executable('ukb', 'src/main.c',\n include_directories: inc,\n- link_with: libukb_a,\n+ link_with: libukb.get_static_lib(),\n install: true,\n )"
},
{
"role": "assistant",
"content": "feat: unify artifact structure, enable release mode"
},
{
"role": "user",
"content": "\ndiff --git a/src/backends/sway.c b/src/backends/sway.c\nindex 229b8bb..c7e8978 100644\n--- a/src/backends/sway.c\n+++ b/src/backends/sway.c\n@@ -37,22 +37,22 @@ typedef union header {\n \n \n static int sway_ipc_open(const char *socket_path) {\n-\tint socketfd;\n-\tif ((socketfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {\n+ int socketfd;\n+ if ((socketfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {\n return -1;\n-\t}\n+ }\n \n-\tstruct sockaddr_un addr = {\n+ struct sockaddr_un addr = {\n .sun_family = AF_UNIX,\n .sun_path = {0},\n };\n-\tstrncpy(addr.sun_path, socket_path, sizeof(addr.sun_path) - 1);\n+ strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path) - 1);\n \n-\tif (connect(socketfd, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) == -1) {\n+ if (connect(socketfd, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) == -1) {\n return -1;\n-\t}\n+ }\n \n-\treturn socketfd;\n+ return socketfd;\n }\n \n static bool sway_ipc_send(int fd, uint32_t type, uint32_t length, const char *data) {"
},
{
"role": "assistant",
"content": "style: fix indentation (tabs & spaces mixing)"
},
{
"role": "user",
"content": "\ndiff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml\nnew file mode 100644\nindex 0000000..4a6e5bc\n--- /dev/null\n+++ b/.github/workflows/workflow.yml\n@@ -0,0 +1,81 @@\n+name: Build\n+\n+on: [push]\n+\n+jobs:\n+ build:\n+ runs-on: ubuntu-latest\n+ permissions:\n+ contents: write\n+ steps:\n+ - uses: actions/checkout@v4\n+\n+ - name: Install dependencies\n+ run: |\n+ sudo apt update\n+ sudo apt install -y \\\n+ mingw-w64 build-essential pkg-config \\\n+ ninja-build meson \\\n+ libjson-c-dev libx11-dev \\\n+ zip\n+\n+ - name: Build (Linux)\n+ run: |\n+ meson setup build.linux\n+ meson compile -C build.linux\n+ meson install -C build.linux --destdir=install\n+\n+ - name: Build (Windows)\n+ run: |\n+ cat > mingw-cross.txt <<EOF\n+ [binaries]\n+ c = 'x86_64-w64-mingw32-gcc'\n+ cpp = 'x86_64-w64-mingw32-g++'\n+ ar = 'x86_64-w64-mingw32-ar'\n+ strip = 'x86_64-w64-mingw32-strip'\n+ pkgconfig = 'x86_64-w64-mingw32-pkg-config'\n+ exe_wrapper = ''\n+\n+ [host_machine]\n+ system = 'windows'\n+ cpu_family = 'x86_64'\n+ cpu = 'x86_64'\n+ endian = 'little'\n+\n+ [built-in options]\n+ prefix = '/'\n+ EOF\n+\n+ meson setup build.win --cross-file mingw-cross.txt\n+ meson compile -C build.win\n+ meson install -C build.win --destdir=install\n+\n+ - name: Package artifacts\n+ env:\n+ ARTIFACT_SUFFIX: ${{ startsWith(github.ref, 'refs/tags/v') && format('-{0}', github.ref_name) || '' }}\n+ run: |\n+ mkdir artifacts\n+\n+ NAME=\"ukb-linux$ARTIFACT_SUFFIX\"\n+ cd build.linux/install\n+ tar czf \"../../artifacts/$NAME.tar.gz\" *\n+ cd ../..\n+\n+ NAME=\"ukb-windows$ARTIFACT_SUFFIX\"\n+ cd build.win/install\n+ zip -r \"../../artifacts/$NAME.zip\" *\n+ cd ../..\n+\n+ - name: Upload artifacts\n+ if: ${{ !startsWith(github.ref, 'refs/tags/v') }}\n+ uses: actions/upload-artifact@v4\n+ with:\n+ name: artifacts\n+ path: artifacts/*\n+\n+ - name: Create Release\n+ if: ${{ startsWith(github.ref, 'refs/tags/v') }}\n+ uses: ncipollo/release-action@v1.16.0\n+ with:\n+ generateReleaseNotes: true\n+ artifacts: \"artifacts/*\"\ndiff --git a/.gitignore b/.gitignore\nindex 276e9cd..2fa41b4 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -4,3 +4,5 @@\n ukb\n .cache/\n compile_commands.json\n+build*/\n+artifacts/"
},
{
"role": "assistant",
"content": "feat: add cicd"
},
{
"role": "user",
"content": "\ndiff --git a/meson.build b/meson.build\nindex 229d3fd..898c3e0 100644\n--- a/meson.build\n+++ b/meson.build\n@@ -11,7 +11,7 @@ deps = []\n platform = host_machine.system()\n \n if platform == 'linux'\n- add_project_arguments('-DPLATFORM=LINUX', language: ['c'])\n+ add_project_arguments('-DPLATFORM_LINUX', language: ['c'])\n lib_src += files(\n 'src/backends/sway.c',\n 'src/backends/xorg.c',\n@@ -20,6 +20,9 @@ if platform == 'linux'\n dependency('json-c', required: true),\n dependency('x11', required: true),\n ]\n+elif platform == 'windows'\n+ add_project_arguments('-DPLATFORM_WINDOWS', language: ['c'])\n+ lib_src += files('src/backends/windows.c')\n else\n error('unknown platform: ' + platform)\n endif\ndiff --git a/src/backends/windows.c b/src/backends/windows.c\nnew file mode 100644\nindex 0000000..491af84\n--- /dev/null\n+++ b/src/backends/windows.c\n@@ -0,0 +1,67 @@\n+#include <stdio.h>\n+#include <stdbool.h>\n+#include <windows.h>\n+\n+#include \"ukb.h\"\n+#include \"../utils.h\"\n+\n+\n+#define POLL_DELAY 1\n+\n+\n+static HKL prev_layout = NULL;\n+static char current_layout[128] = {0};\n+\n+\n+static bool hkl_to_name(HKL hkl, char* dst, size_t n) {\n+ LANGID langid = LOWORD((DWORD_PTR)hkl);\n+ LCID lcid = MAKELCID(langid, SORT_DEFAULT);\n+\n+ char name[LOCALE_NAME_MAX_LENGTH];\n+\n+ if (GetLocaleInfoA(lcid, LOCALE_SENGLANGUAGE, name, LOCALE_NAME_MAX_LENGTH)) {\n+ strncpy(dst, name, n);\n+ return true;\n+ } else {\n+ return false;\n+ }\n+}\n+\n+static HKL poll_layout_switch() {\n+ while(1) {\n+ HWND hwnd = GetForegroundWindow();\n+ DWORD thread_id = GetWindowThreadProcessId(hwnd, NULL);\n+ HKL new_layout = GetKeyboardLayout(thread_id);\n+\n+ if (prev_layout != new_layout) {\n+ prev_layout = new_layout;\n+ return new_layout;\n+ }\n+\n+ Sleep(POLL_DELAY);\n+ }\n+}\n+\n+/********************************* BACKEND ***********************************/\n+\n+static bool windows_can_use(void) {\n+ return true;\n+}\n+\n+static ukb_err_t windows_listen(ukb_layout_cb_t cb) {\n+ while (1) {\n+ HKL layout = poll_layout_switch();\n+ if (!hkl_to_name(layout, current_layout, sizeof(current_layout) - 1)) {\n+ UKB_ERR(\"Unknown layout.\");\n+ }\n+ cb(current_layout);\n+ }\n+\n+ UKB_OK();\n+}\n+\n+const ukb_backend_t ukb_backend_windows = {\n+ .name = \"windows\",\n+ .can_use = windows_can_use,\n+ .listen = windows_listen,\n+};\ndiff --git a/src/ukb.c b/src/ukb.c\nindex ec55ec8..74ed7df 100644\n--- a/src/ukb.c\n+++ b/src/ukb.c\n@@ -11,9 +11,16 @@\n \n /********************************* BACKENDS **********************************/\n \n+#if defined PLATFORM_LINUX\n #define UKB_BACKENDS(M) \\\n M(ukb_backend_sway) \\\n M(ukb_backend_xorg)\n+#elif defined PLATFORM_WINDOWS\n+#define UKB_BACKENDS(M) \\\n+ M(ukb_backend_windows)\n+#else\n+#error \"No platform is set.\"\n+#endif\n \n /*****************************************************************************/"
},
{
"role": "assistant",
"content": "feat(windows): add new backend"
},
{
"role": "user",
"content": "\ndiff --git a/Makefile b/Makefile\ndeleted file mode 100644\nindex 9a8818d..0000000\n--- a/Makefile\n+++ /dev/null\n@@ -1,52 +0,0 @@\n-CC = gcc\n-AR = ar\n-\n-DEPS = json-c x11\n-\n-CFLAGS = -Iinclude -Wall -O2 $(shell pkg-config --cflags $(DEPS))\n-LDFLAGS = $(shell pkg-config --libs $(DEPS))\n-\n-LIB_SRC = src/ukb.c $(wildcard src/backends/*.c)\n-LIB_OBJ = $(LIB_SRC:.c=.o)\n-\n-BIN_SRC = src/main.c\n-BIN_OBJ = $(BIN_SRC:.c=.o)\n-\n-PREFIX ?= /usr/local\n-BIN_DIR = $(PREFIX)/bin\n-LIB_DIR = $(PREFIX)/lib\n-INCLUDE_DIR = $(PREFIX)/include/libukb\n-\n-all: libukb.a libukb.so ukb\n-\n-$(LIB_OBJ): %.o: %.c\n-\t$(CC) $(CFLAGS) -fPIC -DUKB_BACKENDS_INTERNAL -c $< -o $@\n-\n-$(BIN_OBJ): %.o: %.c\n-\t$(CC) $(CFLAGS) -c $< -o $@\n-\n-libukb.so: $(LIB_OBJ)\n-\t$(CC) -shared -o $@ $^ $(LDFLAGS)\n-\n-libukb.a: $(LIB_OBJ)\n-\t$(AR) rcs $@ $^\n-\n-ukb: $(BIN_OBJ) libukb.a\n-\t$(CC) $(BIN_OBJ) -L. -l:libukb.a -o $@ $(LDFLAGS)\n-\n-.PHONY: install\n-install: all\n-\tinstall -d $(BIN_DIR) $(LIB_DIR) $(INCLUDE_DIR)\n-\tinstall -m 0755 ukb $(BIN_DIR)/\n-\tinstall -m 0644 libukb.a libukb.so $(LIB_DIR)/\n-\tinstall -m 0644 include/*.h $(INCLUDE_DIR)/\n-\n-.PHONY: uninstall\n-uninstall:\n-\trm -f $(BIN_DIR)/ukb\n-\trm -f $(LIB_DIR)/libukb.a $(LIB_DIR)/libukb.so\n-\trm -rf $(INCLUDE_DIR)\n-\n-.PHONY: clean\n-clean:\n-\trm -f $(LIB_OBJ) $(BIN_OBJ) ukb libukb.so libukb.a\ndiff --git a/meson.build b/meson.build\nnew file mode 100644\nindex 0000000..229d3fd\n--- /dev/null\n+++ b/meson.build\n@@ -0,0 +1,44 @@\n+project('ukb', 'c',\n+ version: '0.1.0',\n+ default_options: ['warning_level=2', 'optimization=2'],\n+)\n+\n+\n+inc = include_directories('include')\n+lib_src = files('src/ukb.c')\n+deps = []\n+\n+platform = host_machine.system()\n+\n+if platform == 'linux'\n+ add_project_arguments('-DPLATFORM=LINUX', language: ['c'])\n+ lib_src += files(\n+ 'src/backends/sway.c',\n+ 'src/backends/xorg.c',\n+ )\n+ deps += [\n+ dependency('json-c', required: true),\n+ dependency('x11', required: true),\n+ ]\n+else\n+ error('unknown platform: ' + platform)\n+endif\n+\n+\n+install_headers('include/ukb.h', subdir: 'ukb')\n+\n+libukb_kwargs = {\n+ 'include_directories': inc,\n+ 'dependencies': deps,\n+ 'c_args': ['-DUKB_BACKENDS_INTERNAL'],\n+ 'install': true,\n+}\n+libukb_a = static_library('ukb', lib_src, kwargs: libukb_kwargs)\n+libukb_so = shared_library('ukb', lib_src, kwargs: libukb_kwargs)\n+\n+\n+executable('ukb', 'src/main.c',\n+ include_directories: inc,\n+ link_with: libukb_a,\n+ install: true,\n+)"
},
{
"role": "assistant",
"content": "feat: transition to meson build system"
},
{
"role": "user",
"content": "\ndiff --git a/src/backends/sway.c b/src/backends/sway.c\nindex a7dfd9c..229b8bb 100644\n--- a/src/backends/sway.c\n+++ b/src/backends/sway.c\n@@ -80,7 +80,7 @@ static bool sway_ipc_recv(int fd, header_t *h, char **data) {\n left -= n;\n }\n \n- *data = (char*)malloc(h->fields.length);\n+ *data = (char*)calloc(1, h->fields.length + 1);\n left = h->fields.length;\n dst = (uint8_t*)*data;"
},
{
"role": "assistant",
"content": "fix(sway): buffer overflow"
},
{
"role": "user",
"content": "\ndiff --git a/src/backends/xorg.c b/src/backends/xorg.c\nindex 00f6ae8..d74c696 100644\n--- a/src/backends/xorg.c\n+++ b/src/backends/xorg.c\n@@ -89,6 +89,27 @@ static int xorg_open_display() {\n /********************************* BACKEND ***********************************/\n \n static bool xorg_can_use(void) {\n+ // xkblib is pretty much useless when running under xwayland,\n+ // so we'll try to detect xwayland with some simple heuristics.\n+\n+ const char* session = getenv(\"XDG_SESSION_TYPE\");\n+ if (session) {\n+ if (strcmp(session, \"wayland\") == 0) {\n+ return false;\n+ }\n+\n+ if (strcmp(session, \"x11\") != 0) {\n+ // require an additional check if session is neither wayland nor x11\n+ session = NULL;\n+ }\n+ }\n+\n+ if (!session) {\n+ if (getenv(\"WAYLAND_DISPLAY\") != NULL) {\n+ return false;\n+ }\n+ }\n+\n int reason_return = xorg_open_display();\n XCloseDisplay(x_display);\n return reason_return == XkbOD_Success;"
},
{
"role": "assistant",
"content": "feat(xorg): detect xwayland"
},
{
"role": "user",
"content": "\ndiff --git a/src/backends/xorg.c b/src/backends/xorg.c\nindex 86820df..00f6ae8 100644\n--- a/src/backends/xorg.c\n+++ b/src/backends/xorg.c\n@@ -59,7 +59,7 @@ static ukb_err_t xorg_wait_event() {\n \n XEvent event;\n int iret = XNextEvent(x_display, &event);\n- if (!iret) {\n+ if (iret) {\n UKB_ERR(\"XNextEvent failed\");\n }"
},
{
"role": "assistant",
"content": "fix: erroneous error on XNextEvent (#2)"
},
{
"role": "user",
"content": "\ndiff --git a/src/backends/xorg.c b/src/backends/xorg.c\nindex dfb5459..86820df 100644\n--- a/src/backends/xorg.c\n+++ b/src/backends/xorg.c\n@@ -54,7 +54,7 @@ static ukb_err_t update_current_layout() {\n static ukb_err_t xorg_wait_event() {\n Bool bret = XkbSelectEventDetails(x_display, XkbUseCoreKbd, XkbStateNotify, XkbAllStateComponentsMask, XkbGroupStateMask);\n if (!bret) {\n- UKB_ERR(\"XkbSelectEventDetails failed\")\n+ UKB_ERR(\"XkbSelectEventDetails failed\");\n }\n \n XEvent event;\ndiff --git a/src/utils.h b/src/utils.h\nindex fee5425..f15f4d4 100644\n--- a/src/utils.h\n+++ b/src/utils.h\n@@ -2,10 +2,10 @@\n \n #define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))\n \n-#define UKB_OK() return (ukb_err_t) { .msg = NULL };\n-#define UKB_ERR(m) return (ukb_err_t) { .msg = m };\n+#define UKB_OK() return (ukb_err_t) { .msg = NULL }\n+#define UKB_ERR(m) return (ukb_err_t) { .msg = m }\n #define UKB_PROPAGATE(expr) \\\n- { \\\n+ do { \\\n ukb_err_t err = expr; \\\n if (err.msg != NULL) return err; \\\n- };\n+ } while (0)"
},
{
"role": "assistant",
"content": "fix: require semicolons for util macros"
},
{
"role": "user",
"content": "\ndiff --git a/Makefile b/Makefile\nindex 702edec..9a8818d 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1,7 +1,7 @@\n CC = gcc\n AR = ar\n \n-DEPS = json-c\n+DEPS = json-c x11\n \n CFLAGS = -Iinclude -Wall -O2 $(shell pkg-config --cflags $(DEPS))\n LDFLAGS = $(shell pkg-config --libs $(DEPS))\ndiff --git a/src/backends/xorg.c b/src/backends/xorg.c\nindex aebd709..dfb5459 100644\n--- a/src/backends/xorg.c\n+++ b/src/backends/xorg.c\n@@ -32,7 +32,7 @@ static ukb_err_t update_current_layout() {\n }\n \n int num_groups = desc_ptr->ctrls->num_groups;\n- if (xkbState.group >= num_groups) {\n+ if (xkb_state.group >= num_groups) {\n UKB_ERR(\"Group index out of range.\");\n }"
},
{
"role": "assistant",
"content": "fix: x11 linking and incorrect variable name"
}
]
SAMPLES = []
# globals
PROMPT="""You are an assistant that helps user to write semantic commit messages. You will be presented with git diff of the code. Write a single short, concise and meaningful message to describe changes that were made. You can only write a single commit message for the entire diff. The single message that you write has to include ALL the changes, that exist in the diff. You can't skip anything. Git commit messages are LIMITED TO 72 CHARACTERS. YOUR MESSAGE COULD NOT BE LONGER THAN 72 CHARACTERS.
@ -60,71 +167,106 @@ Bear in mind that the `short description` of your commit becomes a globally-uniq
Use the "`" (backtick) symbol when referring to certain parts of code in your commit message."""
with open(f"{os.environ['HOME']}/.secrets/openai.secret") as f:
KEY=f.readline().strip()
REQUEST = {
"model": MODEL,
"messages": [
{
"role": "system",
"content": PROMPT
},
*SAMPLES,
{
"role": "user",
"content": DIFF
},
],
"stream": False,
"options": {
"temperature": 1,
"num_ctx": 117000,
}
}
ps = subprocess.Popen(["git", "diff", "--staged"], stdout = subprocess.PIPE)
DIFF = ps.stdout and ps.stdout.read().decode('utf-8').strip()
if not DIFF or DIFF == "":
die("Nothing to commit!")
# arguemnt parsing
N: int = 5
N: int = 1
argv = iter(sys.argv[1:])
for arg in argv:
if arg == "-n":
N = int(next(argv))
thread = threading.Thread(target = spin, args = ['Generating...'])
thread.start()
r = requests.post("https://api.openai.com/v1/chat/completions", headers={'Authorization': f'Bearer {KEY}'}, json = {
"model": "gpt-4o-mini",
"messages": [
{
"role": "system",
"content": [
{
"type": "text",
"text": PROMPT,
}
]
},
{
"role": "user",
"content": [
{
"type": "text",
"text": DIFF,
}
]
},
],
"response_format": {
"type": "text"
},
"temperature": 1,
"max_completion_tokens": 72,
"n": N,
"top_p": 1,
"frequency_penalty": 0,
"presence_penalty": 0
})
def strip_equal(msg: str, substring: str, n_max: int) -> str:
if n_max <= 0 or msg[0] != substring or msg[-1] != substring:
return msg
return strip_equal(msg[1:-1], substring, n_max-1)
if r.status_code != 200:
state = "fail"
thread.join()
die(f"status code: {r.status_code}\n{r.text}")
state = "done"
thread.join()
def cleanup_string(s: str) -> str:
return strip_equal(s.replace('\n','').strip(), '`', 4)
choices = '# ' + '\n# '.join(map(lambda x: cleanup_string(x['message']['content']), r.json()['choices']))
fd = os.memfd_create("file.txt")
fd_wrapper = os.fdopen(fd, mode="w+")
fd_wrapper.write(choices)
fd_wrapper.flush()
fd_path = f"/proc/{os.getpid()}/fd/{fd}"
os.system(f"git commit -v -e -F- < {fd_path}")
class Spinner:
_thread: threading.Thread | None = None
_state: Literal['loading', 'done', 'fail']
total: int = N
current = 0
@classmethod
def start(cls, text: str):
if cls._thread:
return
cls._state = 'loading'
cls.text = text
cls._thread = threading.Thread(target = cls._spin)
cls._thread.start()
@classmethod
def stop(cls, state: bool = True):
if not cls._thread:
return
cls._state = 'done' if state else 'fail'
cls._thread.join()
@classmethod
def _spin(cls):
interval = 80
spinner = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]
i = 0
while cls._state == "loading":
i = (i + 1) % len(spinner)
print(f"\r{spinner[i]} {cls.text} ({cls.current}/{cls.total})", end=' ')
time.sleep(interval / 1000)
symbol = "✓" if cls._state == "done" else ""
print(f"\r{symbol} {cls.text} ")
def main():
Spinner.start('Generating...')
choices = []
futs = []
with ThreadPoolExecutor(max_workers=1) as ex:
for _ in range(N):
futs.append(ex.submit(requests.post, URL, headers=HEADERS, json=REQUEST))
for fut in futs:
r: requests.Response = fut.result()
Spinner.current += 1
if r.status_code != 200:
Spinner.stop(False)
die(f"status code: {r.status_code}\n{r.text}")
choices.append(r.json())
Spinner.stop()
choices = '# ' + '\n# '.join(map(lambda x: cleanup_string(x['message']['content']), choices))
fd = os.memfd_create("file.txt")
with os.fdopen(fd, mode="w+") as fd_wrapper:
fd_wrapper.write(choices)
fd_wrapper.flush()
os.system(f"git commit -v -e -F- < /proc/{os.getpid()}/fd/{fd}")
try:
main()
finally:
Spinner.stop(False)