From 9400a1b2eede87a2d953b0c754f9c2c96cfb34f8 Mon Sep 17 00:00:00 2001 From: Wojciech Kwolek Date: Sat, 8 Jun 2024 05:29:15 +0200 Subject: initial commit --- .eslintrc.json | 4 ++ .gitignore | 177 ++++++++++++++++++++++++++++++++++++++++++++++++ .prettierrc | 4 ++ CHANGELOG.md | 3 + README.md | 1 + assets/command-icon.png | Bin 0 -> 126104 bytes assets/list-icon.png | Bin 0 -> 1522 bytes bun.lockb | Bin 0 -> 64304 bytes dmenu_raycast | 44 ++++++++++++ package.json | 52 ++++++++++++++ src/index.tsx | 62 +++++++++++++++++ tsconfig.json | 16 +++++ 12 files changed, 363 insertions(+) create mode 100644 .eslintrc.json create mode 100644 .gitignore create mode 100644 .prettierrc create mode 100644 CHANGELOG.md create mode 100644 README.md create mode 100644 assets/command-icon.png create mode 100644 assets/list-icon.png create mode 100755 bun.lockb create mode 100755 dmenu_raycast create mode 100644 package.json create mode 100644 src/index.tsx create mode 100644 tsconfig.json diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..e6258e1 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,4 @@ +{ + "root": true, + "extends": ["@raycast"] +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3f46ce1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,177 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules + +# Raycast specific files +raycast-env.d.ts +.raycast-swift-build +.swiftpm +compiled_raycast_swift + +# misc +.DS_Store + +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/latest/usage/project/#working-with-version-control +.pdm.toml +.pdm-python +.pdm-build/ + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ + diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..b7d51e0 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,4 @@ +{ + "printWidth": 120, + "singleQuote": false +} \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..8306894 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,3 @@ +# dmenu Changelog + +## [Initial Version] - 2024-06-08 \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..13eeb5c --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# dmenu \ No newline at end of file diff --git a/assets/command-icon.png b/assets/command-icon.png new file mode 100644 index 0000000..8c158ec Binary files /dev/null and b/assets/command-icon.png differ diff --git a/assets/list-icon.png b/assets/list-icon.png new file mode 100644 index 0000000..5cb0858 Binary files /dev/null and b/assets/list-icon.png differ diff --git a/bun.lockb b/bun.lockb new file mode 100755 index 0000000..66e9d24 Binary files /dev/null and b/bun.lockb differ diff --git a/dmenu_raycast b/dmenu_raycast new file mode 100755 index 0000000..8e91f55 --- /dev/null +++ b/dmenu_raycast @@ -0,0 +1,44 @@ +#!/usr/bin/env python3 +import json +import sys +import subprocess +from urllib.parse import urlencode, quote +import socket + +EXTENSION = "irth/dmenu" +COMMAND = "index" + +elements = list(sys.stdin) + + +server = socket.socket() +server.bind(("127.0.0.1", 0)) +server.listen(0) + +host, port = server.getsockname() + +arguments = { + "host": host, + "port": str(port), +} + +query = urlencode({"arguments": json.dumps(arguments)}, quote_via=quote) + +url = f"raycast://extensions/{EXTENSION}/{COMMAND}?{query}" + +subprocess.run(["open", url], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + +(conn, _) = server.accept() + +conn.send(f"{len(elements)}\n".encode("utf-8")) +for el in elements: + conn.send(f"{el.strip()}\n".encode("utf-8")) + +result = b"" +while len(data := conn.recv(1024)) != 0: + result += data + +final_result = result.decode("utf-8").strip() +if final_result == '': + exit(1) +print(final_result) diff --git a/package.json b/package.json new file mode 100644 index 0000000..3fd552b --- /dev/null +++ b/package.json @@ -0,0 +1,52 @@ +{ + "$schema": "https://www.raycast.com/schemas/extension.json", + "name": "dmenu", + "title": "dmenu", + "description": "A dmenu like functionality for Raycast", + "icon": "command-icon.png", + "author": "irth", + "license": "MIT", + "commands": [ + { + "name": "index", + "title": "Show a dmenu_raycast option list", + "description": "This is meant to be used programmaticaly via the dmenu_raycast script", + "mode": "view", + "arguments": [ + { + "name": "host", + "placeholder": "Host", + "type": "text", + "required": true + }, + { + "name": "port", + "placeholder": "Port", + "type": "text", + "required": true + } + ] + } + ], + "tools": null, + "dependencies": { + "@raycast/api": "^1.76.0", + "@raycast/utils": "^1.15.0" + }, + "devDependencies": { + "@raycast/eslint-config": "^1.0.6", + "@types/node": "20.8.10", + "@types/react": "18.2.27", + "eslint": "^8.51.0", + "prettier": "^3.0.3", + "typescript": "^5.2.2" + }, + "scripts": { + "build": "ray build -e dist", + "dev": "ray develop", + "fix-lint": "ray lint --fix", + "lint": "ray lint", + "prepublishOnly": "echo \"\\n\\nIt seems like you are trying to publish the Raycast extension to npm.\\n\\nIf you did intend to publish it to npm, remove the \\`prepublishOnly\\` script and rerun \\`npm publish\\` again.\\nIf you wanted to publish it to the Raycast Store instead, use \\`npm run publish\\` instead.\\n\\n\" && exit 1", + "publish": "npx @raycast/api@latest publish" + } +} diff --git a/src/index.tsx b/src/index.tsx new file mode 100644 index 0000000..b300f20 --- /dev/null +++ b/src/index.tsx @@ -0,0 +1,62 @@ +import { ActionPanel, List, Action, closeMainWindow } from "@raycast/api"; +import { connect, Socket } from "net"; +import { showFailureToast } from "@raycast/utils"; +import { useState, useEffect, useRef } from "react"; + +export default function Command({ arguments: { host, port } }: { arguments: { host: string, port: string } }) { + const [elements, setElements] = useState(); + const socket = useRef(); + + useEffect(() => { + const showErr = (err: ErrorEvent) => { + showFailureToast(err.message, { title: "Couldn't connect to the script" }); + setElements([]); + }; + + const s = connect({ host, port: parseInt(port) }) + socket.current = s + s.on('error', showErr); + + let buf: string = ''; + + s.on('data', data => { + buf += data; + + const firstLineEnding = buf.indexOf('\n'); + if (firstLineEnding == -1) return; + + const amount = parseInt(buf.slice(0, firstLineEnding)); + + const lines = buf.slice(firstLineEnding + 1).trim().split("\n"); + if (lines.length != amount) return; + + setElements(lines.map(s => s.trim()).filter(s => s.length != 0)); + }) + + s.on('close', () => closeMainWindow()); + + return () => { + if (socket.current != null) socket.current.end(); + } + }, [host, port]) + + + return ( + + {elements?.map((item, idx) => + { + const s = socket.current; + if (s == null) { + showFailureToast('Socket disconnected') + closeMainWindow(); + return; + } + s.write(item + '\n') + s.end() + }} /> + + } />)} + + ); +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..abb1580 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,16 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "include": ["src/**/*", "raycast-env.d.ts"], + "compilerOptions": { + "lib": ["ES2023"], + "module": "commonjs", + "target": "ES2022", + "strict": true, + "isolatedModules": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "jsx": "react-jsx", + "resolveJsonModule": true + } +} -- cgit v1.2.3