summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWojciech Kwolek <wojciech@kwolek.io>2024-06-08 05:29:15 +0200
committerWojciech Kwolek <wojciech@kwolek.io>2024-06-08 05:29:15 +0200
commit9400a1b2eede87a2d953b0c754f9c2c96cfb34f8 (patch)
tree206ac808fc86f0dded4a20e8af2e2afda7b225ec
initial commit
-rw-r--r--.eslintrc.json4
-rw-r--r--.gitignore177
-rw-r--r--.prettierrc4
-rw-r--r--CHANGELOG.md3
-rw-r--r--README.md1
-rw-r--r--assets/command-icon.pngbin0 -> 126104 bytes
-rw-r--r--assets/list-icon.pngbin0 -> 1522 bytes
-rwxr-xr-xbun.lockbbin0 -> 64304 bytes
-rwxr-xr-xdmenu_raycast44
-rw-r--r--package.json52
-rw-r--r--src/index.tsx62
-rw-r--r--tsconfig.json16
12 files changed, 363 insertions, 0 deletions
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
--- /dev/null
+++ b/assets/command-icon.png
Binary files differ
diff --git a/assets/list-icon.png b/assets/list-icon.png
new file mode 100644
index 0000000..5cb0858
--- /dev/null
+++ b/assets/list-icon.png
Binary files differ
diff --git a/bun.lockb b/bun.lockb
new file mode 100755
index 0000000..66e9d24
--- /dev/null
+++ b/bun.lockb
Binary files 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<string[]>();
+ const socket = useRef<Socket>();
+
+ 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 (
+ <List isLoading={elements === undefined}>
+ {elements?.map((item, idx) => <List.Item title={item} key={idx} actions={
+ <ActionPanel>
+ <Action title="Select" onAction={() => {
+ const s = socket.current;
+ if (s == null) {
+ showFailureToast('Socket disconnected')
+ closeMainWindow();
+ return;
+ }
+ s.write(item + '\n')
+ s.end()
+ }} />
+ </ActionPanel>
+ } />)}
+ </List>
+ );
+}
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
+ }
+}