├── .build-and-release.sh ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.yml │ ├── config.yml │ └── feature_request.yml ├── caches │ ├── devdocs-keyword-slug-map.json │ └── obsidian-help-index.json ├── dependabot.yml ├── pull_request_template.md └── workflows │ ├── alfred-workflow-release.yml │ ├── markdownlint.yml │ ├── pr-title.yml │ ├── stale-bot.yml │ ├── update-devdocs.yml │ └── update-obsidian-help-index.yml ├── .gitignore ├── .markdownlint.yaml ├── .rsync-exclude ├── .typos.toml ├── 02AF1097-A098-43E8-91E4-28B34C6C010C.png ├── 090678C4-E32D-408A-A3F2-88B39DCCE851.png ├── 110DF925-B50C-4ABC-B412-2F7C48A78D72.png ├── 321BD266-1E62-4C75-A792-85239F1268B0.png ├── 33BD334F-B73B-4462-9E9E-0B53BBC46B25.png ├── 3CA7F398-9E2A-467B-B1B1-CC0DBBCB20A5.png ├── 3F1227C0-7373-4B26-BADB-05F279D75A62.png ├── 3F695A74-EC6B-4436-9063-9A618A8CC0B8.png ├── 582225D7-8F6C-468C-A212-86ACFA5F026C.png ├── 5A2D4239-FC30-482F-831B-D2E261B44B7F.png ├── 5D0C789F-E59F-4435-8AB1-84CBA3CF65DC.png ├── 71F9A459-55CC-41D5-A1FA-4424B696D4E3.png ├── 807968C5-83D0-4F80-8188-636A8D536DBE.png ├── A89D07AD-BB4E-4D63-B7B7-DDB763334AEC.png ├── BE9F5DBB-FD56-4FB5-8D27-682A7E1D3BFA.png ├── E0497D01-2949-468B-B5C6-D6837344A30B.png ├── FC4A9CCB-0458-42DE-9CFE-4110B7E0CADF.png ├── Justfile ├── LICENSE ├── README.md ├── icon.png ├── info.plist └── scripts ├── devdocs ├── icons │ ├── README.md │ ├── bash.png │ ├── cani.png │ ├── css.png │ ├── dom.png │ ├── electron.png │ ├── esbuild.png │ ├── git.png │ ├── hs.png │ ├── html.png │ ├── jq.png │ ├── js.png │ ├── jsdoc.png │ ├── lua.png │ ├── man.png │ ├── mt.png │ ├── node.png │ ├── np.png │ ├── npm.png │ ├── pd.png │ ├── py.png │ └── ts.png ├── open-at-original-site.js ├── search-devdocs.js └── update-devdocs.mjs ├── extra-utilities ├── .ignore ├── appid.js ├── appid.sh ├── apple-keycodes.json ├── applescript-dictionaries.js ├── color-svgs │ ├── aliceblue.svg │ ├── antiquewhite.svg │ ├── aqua.svg │ ├── aquamarine.svg │ ├── azure.svg │ ├── beige.svg │ ├── bisque.svg │ ├── black.svg │ ├── blanchedalmond.svg │ ├── blue.svg │ ├── blueviolet.svg │ ├── brown.svg │ ├── burlywood.svg │ ├── cadetblue.svg │ ├── chartreuse.svg │ ├── chocolate.svg │ ├── coral.svg │ ├── cornflowerblue.svg │ ├── cornsilk.svg │ ├── crimson.svg │ ├── cyan.svg │ ├── darkblue.svg │ ├── darkcyan.svg │ ├── darkgoldenrod.svg │ ├── darkgray.svg │ ├── darkgreen.svg │ ├── darkgrey.svg │ ├── darkkhaki.svg │ ├── darkmagenta.svg │ ├── darkolivegreen.svg │ ├── darkorange.svg │ ├── darkorchid.svg │ ├── darkred.svg │ ├── darksalmon.svg │ ├── darkseagreen.svg │ ├── darkslateblue.svg │ ├── darkslategray.svg │ ├── darkslategrey.svg │ ├── darkturquoise.svg │ ├── darkviolet.svg │ ├── deeppink.svg │ ├── deepskyblue.svg │ ├── dimgray.svg │ ├── dimgrey.svg │ ├── dodgerblue.svg │ ├── firebrick.svg │ ├── floralwhite.svg │ ├── forestgreen.svg │ ├── fuchsia.svg │ ├── gainsboro.svg │ ├── ghostwhite.svg │ ├── gold.svg │ ├── goldenrod.svg │ ├── gray.svg │ ├── green.svg │ ├── greenyellow.svg │ ├── grey.svg │ ├── honeydew.svg │ ├── hotpink.svg │ ├── indianred.svg │ ├── indigo.svg │ ├── ivory.svg │ ├── khaki.svg │ ├── lavender.svg │ ├── lavenderblush.svg │ ├── lawngreen.svg │ ├── lemonchiffon.svg │ ├── lightblue.svg │ ├── lightcoral.svg │ ├── lightcyan.svg │ ├── lightgoldenrodyellow.svg │ ├── lightgray.svg │ ├── lightgreen.svg │ ├── lightgrey.svg │ ├── lightpink.svg │ ├── lightsalmon.svg │ ├── lightseagreen.svg │ ├── lightskyblue.svg │ ├── lightslategray.svg │ ├── lightslategrey.svg │ ├── lightsteelblue.svg │ ├── lightyellow.svg │ ├── lime.svg │ ├── limegreen.svg │ ├── linen.svg │ ├── magenta.svg │ ├── maroon.svg │ ├── mediumaquamarine.svg │ ├── mediumblue.svg │ ├── mediumorchid.svg │ ├── mediumpurple.svg │ ├── mediumseagreen.svg │ ├── mediumslateblue.svg │ ├── mediumspringgreen.svg │ ├── mediumturquoise.svg │ ├── mediumvioletred.svg │ ├── midnightblue.svg │ ├── mintcream.svg │ ├── mistyrose.svg │ ├── moccasin.svg │ ├── navajowhite.svg │ ├── navy.svg │ ├── oldlace.svg │ ├── olive.svg │ ├── olivedrab.svg │ ├── orange.svg │ ├── orangered.svg │ ├── orchid.svg │ ├── palegoldenrod.svg │ ├── palegreen.svg │ ├── paleturquoise.svg │ ├── palevioletred.svg │ ├── papayawhip.svg │ ├── peachpuff.svg │ ├── peru.svg │ ├── pink.svg │ ├── plum.svg │ ├── powderblue.svg │ ├── purple.svg │ ├── rebeccapurple.svg │ ├── red.svg │ ├── rosybrown.svg │ ├── royalblue.svg │ ├── saddlebrown.svg │ ├── salmon.svg │ ├── sandybrown.svg │ ├── seagreen.svg │ ├── seashell.svg │ ├── sienna.svg │ ├── silver.svg │ ├── skyblue.svg │ ├── slateblue.svg │ ├── slategray.svg │ ├── slategrey.svg │ ├── snow.svg │ ├── springgreen.svg │ ├── steelblue.svg │ ├── tan.svg │ ├── teal.svg │ ├── thistle.svg │ ├── tomato.svg │ ├── turquoise.svg │ ├── violet.svg │ ├── wheat.svg │ ├── white.svg │ ├── whitesmoke.svg │ ├── yellow.svg │ └── yellowgreen.svg ├── get-window-information.applescript ├── http-status-codes.json ├── named-css-colors.csv ├── named-css-colors.js ├── reload-cache.js └── sounds-preview.js └── manual-docs-searches ├── CodeMirror.png ├── biome-docs-search.js ├── build-obsidian-help-index.mjs ├── ddg-help.js ├── obsi-developer-docs-search.js ├── pandoc-docs.js ├── ruff-rules.js ├── shellcheck-wiki.js ├── wezterm-docs-search.js └── yq-docs.js /.build-and-release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | #─────────────────────────────────────────────────────────────────────────────── 3 | 4 | # goto git root 5 | cd "$(git rev-parse --show-toplevel)" || return 1 6 | 7 | # Prompt for next version number 8 | current_version=$(plutil -extract version xml1 -o - info.plist | sed -n 's/.*\(.*\)<\/string>.*/\1/p') 9 | echo "current version: $current_version" 10 | echo -n " next version: " 11 | read -r next_version 12 | echo "────────────────────────" 13 | 14 | # GUARD 15 | if [[ -z "$next_version" || "$next_version" == "$current_version" ]]; then 16 | print "\033[1;31mInvalid version number.\033[0m" 17 | return 1 18 | fi 19 | 20 | # update version number in THE REPO'S `info.plist` 21 | plutil -replace version -string "$next_version" info.plist 22 | 23 | #─────────────────────────────────────────────────────────────────────────────── 24 | # INFO this assumes the local folder is named the same as the github repo 25 | # 1. update version number in LOCAL `info.plist` 26 | # 2. convenience: copy download link for current version 27 | 28 | # update version number in LOCAL `info.plist` 29 | prefs_location=$(defaults read com.runningwithcrayons.Alfred-Preferences syncfolder | sed "s|^~|$HOME|") 30 | workflow_uid="$(basename "$PWD")" 31 | local_info_plist="$prefs_location/Alfred.alfredpreferences/workflows/$workflow_uid/info.plist" 32 | if [[ -f "$local_info_plist" ]] ; then 33 | plutil -replace version -string "$next_version" "$local_info_plist" 34 | else 35 | print "\033[1;33mCould not increment version, local \`info.plist\` not found: '$local_info_plist'\033[0m" 36 | return 1 37 | fi 38 | 39 | # copy download link for current version 40 | msg="Available in the Alfred Gallery in 1-2 days, or directly by downloading the latest release here:" 41 | github_user=$(git remote --verbose | head -n1 | sed -E 's/.*github.com[:\](.*)\/.*/\1/') 42 | url="https://github.com/$github_user/$workflow_uid/releases/download/$next_version/${workflow_uid}.alfredworkflow" 43 | echo -n "$msg $url" | pbcopy 44 | 45 | #─────────────────────────────────────────────────────────────────────────────── 46 | 47 | # commit and push 48 | git add --all && 49 | git commit -m "release: $next_version" && 50 | git pull --no-progress && 51 | git push --no-progress && 52 | git tag "$next_version" && # pushing a tag triggers the github release action 53 | git push --no-progress origin --tags 54 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # https://docs.github.com/en/github/administering-a-repository/managing-repository-settings/displaying-a-sponsor-button-in-your-repository 2 | 3 | custom: https://www.paypal.me/ChrisGrieser 4 | ko_fi: pseudometa 5 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.yml: -------------------------------------------------------------------------------- 1 | name: Bug Report 2 | description: File a bug report 3 | title: "[Bug]: " 4 | labels: ["bug"] 5 | body: 6 | - type: textarea 7 | id: bug-description 8 | attributes: 9 | label: Bug Description 10 | description: A clear and concise description of the bug. 11 | validations: 12 | required: true 13 | - type: textarea 14 | id: screenshot 15 | attributes: 16 | label: Relevant Screenshot 17 | description: If applicable, add screenshots or a screen recording to help explain your problem. 18 | - type: textarea 19 | id: reproduction-steps 20 | attributes: 21 | label: To Reproduce 22 | description: Steps to reproduce the problem 23 | placeholder: | 24 | For example: 25 | 1. Go to '...' 26 | 2. Click on '...' 27 | 3. Scroll down to '...' 28 | - type: textarea 29 | id: debugging-log 30 | attributes: 31 | label: Debugging Log 32 | description: "You can get a debugging log by opening the workflow in Alfred preferences and pressing `⌘ + D`. A small window will open up which will log everything happening during the execution of the Workflow. Use the malfunctioning part of the workflow once more, copy the content of the log window, and paste it here. If the debugging log is long, please attach it as file instead of pasting everything in here." 33 | render: Text 34 | validations: 35 | required: true 36 | - type: textarea 37 | id: workflow-configuration 38 | attributes: 39 | label: Workflow Configuration 40 | description: "Please add a screenshot of your [workflow configuration](https://www.alfredapp.com/help/workflows/user-configuration/)." 41 | validations: 42 | required: true 43 | - type: checkboxes 44 | id: checklist 45 | attributes: 46 | label: Checklist 47 | options: 48 | - label: I have [updated to the latest version](./releases/latest) of this workflow. 49 | required: true 50 | - label: I am using Alfred 5. (Older versions are not supported anymore.) 51 | required: true 52 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yml: -------------------------------------------------------------------------------- 1 | name: Feature request 2 | description: Suggest an idea 3 | title: "Feature Request: " 4 | labels: ["enhancement"] 5 | body: 6 | - type: checkboxes 7 | id: checklist 8 | attributes: 9 | label: Checklist 10 | options: 11 | - label: "I have read the plugin's documentation." 12 | required: true 13 | - label: The feature would be useful to more users than just me. 14 | required: true 15 | - type: textarea 16 | id: feature-requested 17 | attributes: 18 | label: Feature Requested 19 | description: A clear and concise description of the feature. 20 | validations: 21 | required: true 22 | - type: textarea 23 | id: screenshot 24 | attributes: 25 | label: Relevant Screenshot 26 | description: If applicable, add screenshots or a screen recording to help explain the request. 27 | 28 | -------------------------------------------------------------------------------- /.github/caches/devdocs-keyword-slug-map.json: -------------------------------------------------------------------------------- 1 | { 2 | "ng": "angular", 3 | "angularjs": "angularjs~1.8", 4 | "ansible": "ansible", 5 | "apache_http_server": "apache_http_server", 6 | "apache_pig": "apache_pig~0.17", 7 | "astro": "astro", 8 | "async": "async", 9 | "axios": "axios", 10 | "babel": "babel~7", 11 | "bb": "backbone", 12 | "bash": "bash", 13 | "bazel": "bazel~8.0", 14 | "bluebird": "bluebird", 15 | "bootstrap": "bootstrap~5", 16 | "bottle": "bottle~0.12", 17 | "bower": "bower", 18 | "c": "c", 19 | "c++": "cpp", 20 | "cakephp": "cakephp~4.4", 21 | "chai": "chai", 22 | "chef": "chef~18", 23 | "click": "click", 24 | "clojure": "clojure~1.11", 25 | "cmake": "cmake", 26 | "codeception": "codeception", 27 | "codeceptjs": "codeceptjs", 28 | "codeigniter": "codeigniter~4", 29 | "cs": "coffeescript~2", 30 | "composer": "composer", 31 | "cordova": "cordova~9", 32 | "cr": "crystal", 33 | "css": "css", 34 | "cypress": "cypress", 35 | "d": "d", 36 | "d3": "d3~7", 37 | "dart": "dart~2", 38 | "date_fns": "date_fns", 39 | "deno": "deno~2", 40 | "django": "django~5.2", 41 | "django_rest_framework": "django_rest_framework", 42 | "docker": "docker", 43 | "dojo": "dojo", 44 | "drupal": "drupal~8", 45 | "duckdb": "duckdb", 46 | "eigen3": "eigen3", 47 | "electron": "electron", 48 | "elisp": "elisp", 49 | "ex": "elixir~1.18", 50 | "ember": "ember~4", 51 | "enzyme": "enzyme", 52 | "erlang": "erlang~26", 53 | "esbuild": "esbuild", 54 | "eslint": "eslint", 55 | "express": "express", 56 | "falcon": "falcon~2.0", 57 | "fastapi": "fastapi", 58 | "fish": "fish~4.0", 59 | "flask": "flask", 60 | "flow": "flow", 61 | "fluture": "fluture", 62 | "gcc": "gcc~14", 63 | "git": "git", 64 | "gnu_fortran": "gnu_fortran~14", 65 | "gnu_make": "gnu_make", 66 | "gnu_cobol": "gnu_cobol", 67 | "gnuplot": "gnuplot", 68 | "go": "go", 69 | "godot": "godot~4.2", 70 | "graphite": "graphite", 71 | "groovy": "groovy~4.0", 72 | "grunt": "grunt", 73 | "gtk": "gtk~4.0", 74 | "hs": "hammerspoon", 75 | "handlebars": "handlebars", 76 | "hapi": "hapi", 77 | "haproxy": "haproxy~3.0", 78 | "haskell": "haskell~9", 79 | "haxe": "haxe", 80 | "homebrew": "homebrew", 81 | "html": "html", 82 | "htmx": "htmx", 83 | "http": "http", 84 | "i3": "i3", 85 | "immutable": "immutable", 86 | "influxdata": "influxdata", 87 | "jasmine": "jasmine", 88 | "js": "javascript", 89 | "jekyll": "jekyll~4", 90 | "jest": "jest", 91 | "jinja": "jinja~3.1", 92 | "joi": "joi", 93 | "jq": "jq", 94 | "$": "jquery", 95 | "jquerymobile": "jquerymobile", 96 | "jqueryui": "jqueryui", 97 | "jsdoc": "jsdoc", 98 | "jl": "julia~1.11", 99 | "ko": "knockout", 100 | "koa": "koa", 101 | "kotlin": "kotlin~1.9", 102 | "kubectl": "kubectl", 103 | "k8s": "kubernetes", 104 | "laravel": "laravel~11", 105 | "latex": "latex", 106 | "leaflet": "leaflet~1.9", 107 | "ls": "less~4", 108 | "man": "man", 109 | "liquid": "liquid", 110 | "_": "lodash~4", 111 | "lua": "lua~5.4", 112 | "löve": "love", 113 | "mariadb": "mariadb", 114 | "mn": "marionette~4", 115 | "md": "markdown", 116 | "plt": "matplotlib", 117 | "meteor": "meteor~1.5", 118 | "mocha": "mocha", 119 | "mdr": "modernizr", 120 | "mt": "moment", 121 | "moment_timezone": "moment_timezone", 122 | "mongoose": "mongoose", 123 | "nextjs": "nextjs", 124 | "ngx": "nginx", 125 | "nginx_lua_module": "nginx_lua_module", 126 | "nim": "nim", 127 | "nix": "nix", 128 | "node": "node", 129 | "nokogiri": "nokogiri", 130 | "npm": "npm", 131 | "np": "numpy~2.0", 132 | "nushell": "nushell", 133 | "ocaml": "ocaml", 134 | "octave": "octave~9", 135 | "opengl": "opengl~4", 136 | "java": "openjdk~21", 137 | "openlayers": "openlayers", 138 | "opentsdb": "opentsdb", 139 | "padrino": "padrino", 140 | "pd": "pandas~2", 141 | "perl": "perl~5.38", 142 | "phalcon": "phalcon~3", 143 | "phaser": "phaser", 144 | "phoenix": "phoenix", 145 | "php": "php", 146 | "phpunit": "phpunit", 147 | "playwright": "playwright", 148 | "point_cloud_library": "point_cloud_library", 149 | "pony": "pony", 150 | "pg": "postgresql~17", 151 | "prettier": "prettier", 152 | "pug": "pug", 153 | "puppeteer": "puppeteer", 154 | "pygame": "pygame", 155 | "py": "python~3.13", 156 | "pytorch": "pytorch~2", 157 | "q": "q", 158 | "qt": "qt", 159 | "qunit": "qunit", 160 | "r": "r", 161 | "ramda": "ramda", 162 | "react": "react", 163 | "react_bootstrap": "react_bootstrap", 164 | "react_native": "react_native", 165 | "react_router": "react_router", 166 | "reactivex": "reactivex", 167 | "redis": "redis", 168 | "redux": "redux", 169 | "relay": "relay~10", 170 | "requests": "requests", 171 | "requirejs": "requirejs", 172 | "rethinkdb": "rethinkdb~javascript", 173 | "rb": "ruby~3.4", 174 | "minitest": "minitest", 175 | "ror": "rails~8.0", 176 | "rs": "rust", 177 | "rxjs": "rxjs", 178 | "saltstack": "saltstack", 179 | "sanctuary": "sanctuary", 180 | "sanctuary_def": "sanctuary_def", 181 | "sanctuary_type_classes": "sanctuary_type_classes", 182 | "scss": "sass", 183 | "scala": "scala~3.2", 184 | "scikit_image": "scikit_image", 185 | "scikit_learn": "scikit_learn", 186 | "sequelize": "sequelize~6", 187 | "sinon": "sinon~15", 188 | "socketio": "socketio~4", 189 | "spring_boot": "spring_boot", 190 | "sqlite": "sqlite", 191 | "statsmodels": "statsmodels", 192 | "cani": "browser_support_tables", 193 | "svelte": "svelte", 194 | "svg": "svg", 195 | "symfony": "symfony~4.1", 196 | "tailwindcss": "tailwindcss", 197 | "tcl_tk": "tcl_tk", 198 | "tf": "tensorflow", 199 | "tensorflow_cpp": "tensorflow_cpp", 200 | "terraform": "terraform", 201 | "threejs": "threejs", 202 | "trio": "trio", 203 | "twig": "twig~3", 204 | "ts": "typescript", 205 | "underscore": "underscore", 206 | "vagrant": "vagrant", 207 | "varnish": "varnish", 208 | "vite": "vite", 209 | "vitest": "vitest", 210 | "vue": "vue~3", 211 | "vue_router": "vue_router~4", 212 | "vueuse": "vueuse", 213 | "vuex": "vuex~4", 214 | "vulkan": "vulkan", 215 | "wagtail": "wagtail", 216 | "dom": "dom", 217 | "web_extensions": "web_extensions", 218 | "webpack": "webpack~5", 219 | "werkzeug": "werkzeug", 220 | "wordpress": "wordpress", 221 | "xslt_xpath": "xslt_xpath", 222 | "yarn": "yarn", 223 | "yii": "yii~2.0", 224 | "zig": "zig" 225 | } -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | schedule: 6 | interval: "weekly" 7 | commit-message: 8 | prefix: "chore(dependabot): " 9 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## What problem does this PR solve? 2 | 3 | ## How does the PR solve it? 4 | 5 | ## Checklist 6 | - [ ] Used only `camelCase` variable names. 7 | - [ ] If functionality is added or modified, also made respective changes to the 8 | `README.md` and the internal workflow documentation. 9 | -------------------------------------------------------------------------------- /.github/workflows/alfred-workflow-release.yml: -------------------------------------------------------------------------------- 1 | name: Alfred Workflow Release 2 | 3 | on: 4 | push: 5 | tags: ["*"] 6 | 7 | env: 8 | WORKFLOW_NAME: ${{ github.event.repository.name }} 9 | 10 | #─────────────────────────────────────────────────────────────────────────────── 11 | 12 | jobs: 13 | build: 14 | runs-on: macos-latest 15 | permissions: { contents: write } 16 | steps: 17 | - name: Checkout 18 | uses: actions/checkout@v4 19 | 20 | - name: Build .alfredworkflow 21 | run: | 22 | zip --recurse-paths --symlinks "${{ env.WORKFLOW_NAME }}.alfredworkflow" . \ 23 | --exclude "README.md" ".git*" "Justfile" ".build-and-release.sh" \ 24 | ".rsync-exclude" ".editorconfig" ".typos.toml" ".markdownlint.*" 25 | 26 | - name: Create release notes 27 | id: release_notes 28 | uses: mikepenz/release-changelog-builder-action@v5 29 | env: 30 | GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" 31 | with: 32 | mode: "COMMIT" 33 | configurationJson: | 34 | { 35 | "label_extractor": [{ 36 | "pattern": "^(\\w+)(\\([\\w\\-\\.]+\\))?(!)?: .+", 37 | "on_property": "title", 38 | "target": "$1" 39 | }], 40 | "categories": [ 41 | { "title": "## ⚠️ Breaking changes", "labels": ["break"] }, 42 | { "title": "## 🚀 New features", "labels": ["feat", "improv"] }, 43 | { "title": "## 🛠️ Fixes", "labels": ["fix", "perf", "chore"] }, 44 | { "title": "## 👾 Other", "labels": [] } 45 | ], 46 | "ignore_labels": ["release", "bump"] 47 | } 48 | 49 | - name: Release 50 | uses: softprops/action-gh-release@v2 51 | with: 52 | token: ${{ secrets.GITHUB_TOKEN }} 53 | body: ${{ steps.release_notes.outputs.changelog }} 54 | files: ${{ env.WORKFLOW_NAME }}.alfredworkflow 55 | -------------------------------------------------------------------------------- /.github/workflows/markdownlint.yml: -------------------------------------------------------------------------------- 1 | name: Markdownlint check 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | paths: 7 | - "**.md" 8 | - ".github/workflows/markdownlint.yml" 9 | - ".markdownlint.*" # markdownlint config files 10 | pull_request: 11 | paths: 12 | - "**.md" 13 | 14 | jobs: 15 | markdownlint: 16 | name: Markdownlint 17 | runs-on: ubuntu-latest 18 | steps: 19 | - uses: actions/checkout@v4 20 | - uses: DavidAnson/markdownlint-cli2-action@v20 21 | with: 22 | globs: "**/*.md" 23 | -------------------------------------------------------------------------------- /.github/workflows/pr-title.yml: -------------------------------------------------------------------------------- 1 | name: PR title 2 | 3 | on: 4 | pull_request_target: 5 | types: 6 | - opened 7 | - edited 8 | - synchronize 9 | - reopened 10 | - ready_for_review 11 | 12 | permissions: 13 | pull-requests: read 14 | 15 | jobs: 16 | semantic-pull-request: 17 | name: Check PR title 18 | runs-on: ubuntu-latest 19 | steps: 20 | - uses: amannn/action-semantic-pull-request@v5 21 | env: 22 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 23 | with: 24 | requireScope: false 25 | subjectPattern: ^(?![A-Z]).+$ # disallow title starting with capital 26 | types: | # add `improv` to the list of allowed types 27 | improv 28 | fix 29 | feat 30 | refactor 31 | build 32 | ci 33 | style 34 | test 35 | chore 36 | perf 37 | docs 38 | break 39 | revert 40 | -------------------------------------------------------------------------------- /.github/workflows/stale-bot.yml: -------------------------------------------------------------------------------- 1 | name: Stale bot 2 | on: 3 | schedule: 4 | - cron: "18 04 * * 3" 5 | 6 | permissions: 7 | issues: write 8 | pull-requests: write 9 | 10 | jobs: 11 | stale: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Close stale issues 15 | uses: actions/stale@v9 16 | with: 17 | repo-token: ${{ secrets.GITHUB_TOKEN }} 18 | 19 | # DOCS https://github.com/actions/stale#all-options 20 | days-before-stale: 180 21 | days-before-close: 7 22 | stale-issue-label: "Stale" 23 | stale-issue-message: | 24 | This issue has been automatically marked as stale. 25 | **If this issue is still affecting you, please leave any comment**, for example "bump", and it will be kept open. 26 | close-issue-message: | 27 | This issue has been closed due to inactivity, and will not be monitored. 28 | -------------------------------------------------------------------------------- /.github/workflows/update-devdocs.yml: -------------------------------------------------------------------------------- 1 | name: Update Devdocs 2 | 3 | on: 4 | schedule: 5 | - cron: "15 2 2,15 * *" # twice per month (2:15 at the 2nd and 15th of the month) 6 | 7 | workflow_dispatch: # triggering manually 8 | 9 | push: 10 | paths: # when this file or the script for re-indexing is changed 11 | - .github/workflows/update-devdocs.yml 12 | - scripts/devdocs/update-devdocs.mjs 13 | branches: 14 | - main # prevents triggering on temporary branches created when making a release 15 | 16 | permissions: 17 | contents: write 18 | 19 | #─────────────────────────────────────────────────────────────────────────────── 20 | 21 | jobs: 22 | build: 23 | runs-on: macos-latest 24 | steps: 25 | - name: checkout 26 | uses: actions/checkout@v4 27 | 28 | - name: setup node 29 | uses: actions/setup-node@v4 30 | with: 31 | node-version: "23.x" 32 | 33 | - name: update devdocs & commit 34 | run: | 35 | node ./scripts/devdocs/update-devdocs.mjs 36 | 37 | # GUARD if only the `info.plist` was updated, it's due to formatting changes 38 | # and there is not actual update to be made. 39 | updated_files=$(git diff --name-only) 40 | if ! echo "$updated_files" | grep -q "devdocs-keyword-slug-map"; then 41 | echo "No changes to commit." 42 | exit 0 43 | fi 44 | 45 | # determine what changes occurred and add them to the commit message 46 | changes=$( 47 | git diff **/devdocs-keyword-slug-map.json | 48 | tail +6 | # remove diff header 49 | grep "^+" | # only added lines 50 | cut -d'"' -f4 | # only changed value 51 | awk 'ORS=", "' | # merge lines with commas 52 | sed -e 's/, $//' # remove trailing comma 53 | ) 54 | # do not stop workflow here, just indicate that the change detection 55 | # has an issue 56 | [[ -z "$changes" ]] && changes="???" 57 | 58 | git add --all 59 | git commit --message "chore: auto-update devdocs ($changes)" \ 60 | --author="🤖 Automated GitHub Action" 61 | git push 62 | -------------------------------------------------------------------------------- /.github/workflows/update-obsidian-help-index.yml: -------------------------------------------------------------------------------- 1 | name: Update Obsidian Help Index 2 | 3 | on: 4 | schedule: 5 | # INFO 2h later than the auto-update of devdocs to avoid commit conflicts 6 | - cron: "15 4 2,15 * *" # twice per month (4:15 at the 2nd and 15th of the month) 7 | 8 | workflow_dispatch: # triggering manually 9 | 10 | push: 11 | paths: # when this file or the script for re-indexing is changed 12 | - .github/workflows/update-obsidian-help-index.yml 13 | - scripts/manual-docs-searches/build-obsidian-help-index.mjs 14 | branches: 15 | - main # prevents triggering on temporary branches created when making a release 16 | 17 | permissions: 18 | contents: write 19 | 20 | #─────────────────────────────────────────────────────────────────────────────── 21 | 22 | jobs: 23 | build: 24 | runs-on: macos-latest 25 | steps: 26 | - name: checkout 27 | uses: actions/checkout@v4 28 | 29 | - name: setup node 30 | uses: actions/setup-node@v4 31 | with: 32 | node-version: "23.x" 33 | 34 | - name: update documentation search index 35 | env: 36 | # https://docs.github.com/en/actions/security-for-github-actions/security-guides/automatic-token-authentication 37 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 38 | run: | 39 | node ./scripts/manual-docs-searches/build-obsidian-help-index.mjs 40 | exit $? # inherit exit code 41 | 42 | - name: commit 43 | uses: stefanzweifel/git-auto-commit-action@v5 44 | with: 45 | commit_message: "chore: auto-update Obsidian help index" 46 | branch: ${{ github.head_ref }} 47 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Mac 2 | .DS_Store 3 | 4 | # Alfred 5 | prefs.plist 6 | *.alfredworkflow 7 | -------------------------------------------------------------------------------- /.markdownlint.yaml: -------------------------------------------------------------------------------- 1 | # Defaults https://github.com/DavidAnson/markdownlint/blob/main/schema/.markdownlint.yaml 2 | # DOCS https://github.com/markdownlint/markdownlint/blob/main/docs/RULES.md 3 | #─────────────────────────────────────────────────────────────────────────────── 4 | 5 | # MODIFIED SETTINGS 6 | blanks-around-headings: 7 | lines_below: 0 # space waster 8 | ul-style: { style: sublist } 9 | 10 | # not autofixable 11 | ol-prefix: { style: ordered } 12 | line-length: 13 | tables: false 14 | code_blocks: false 15 | no-inline-html: 16 | allowed_elements: [img, details, summary, kbd, a, br] 17 | 18 | #───────────────────────────────────────────────────────────────────────────── 19 | # DISABLED 20 | ul-indent: false # not compatible with using tabs 21 | no-hard-tabs: false # taken care of by editorconfig 22 | blanks-around-lists: false # space waster 23 | first-line-heading: false # e.g., ignore-comments 24 | no-emphasis-as-heading: false # sometimes useful 25 | -------------------------------------------------------------------------------- /.rsync-exclude: -------------------------------------------------------------------------------- 1 | # vim: ft=gitignore 2 | #─────────────────────────────────────────────────────────────────────────────── 3 | 4 | # git 5 | .git/ 6 | .gitignore 7 | 8 | # Alfred 9 | prefs.plist 10 | .rsync-exclude 11 | 12 | # docs 13 | docs/ 14 | LICENSE 15 | # INFO leading `/` -> ignore only the README in the root, not in subfolders 16 | /README.md 17 | 18 | # build 19 | Justfile 20 | .github/ 21 | .build-and-release.sh 22 | 23 | # linter & types 24 | .typos.toml 25 | .editorconfig 26 | .markdownlint.yaml 27 | jxa-globals.d.ts 28 | jsconfig.json 29 | alfred.d.ts 30 | -------------------------------------------------------------------------------- /.typos.toml: -------------------------------------------------------------------------------- 1 | [default.extend-words] 2 | caf = "caf" # file extension for sounds 3 | -------------------------------------------------------------------------------- /02AF1097-A098-43E8-91E4-28B34C6C010C.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisgrieser/alfred-docs-searches/f0f9f41fa408c877facad81e27eee3e759520b31/02AF1097-A098-43E8-91E4-28B34C6C010C.png -------------------------------------------------------------------------------- /090678C4-E32D-408A-A3F2-88B39DCCE851.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisgrieser/alfred-docs-searches/f0f9f41fa408c877facad81e27eee3e759520b31/090678C4-E32D-408A-A3F2-88B39DCCE851.png -------------------------------------------------------------------------------- /110DF925-B50C-4ABC-B412-2F7C48A78D72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisgrieser/alfred-docs-searches/f0f9f41fa408c877facad81e27eee3e759520b31/110DF925-B50C-4ABC-B412-2F7C48A78D72.png -------------------------------------------------------------------------------- /321BD266-1E62-4C75-A792-85239F1268B0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisgrieser/alfred-docs-searches/f0f9f41fa408c877facad81e27eee3e759520b31/321BD266-1E62-4C75-A792-85239F1268B0.png -------------------------------------------------------------------------------- /33BD334F-B73B-4462-9E9E-0B53BBC46B25.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisgrieser/alfred-docs-searches/f0f9f41fa408c877facad81e27eee3e759520b31/33BD334F-B73B-4462-9E9E-0B53BBC46B25.png -------------------------------------------------------------------------------- /3CA7F398-9E2A-467B-B1B1-CC0DBBCB20A5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisgrieser/alfred-docs-searches/f0f9f41fa408c877facad81e27eee3e759520b31/3CA7F398-9E2A-467B-B1B1-CC0DBBCB20A5.png -------------------------------------------------------------------------------- /3F1227C0-7373-4B26-BADB-05F279D75A62.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisgrieser/alfred-docs-searches/f0f9f41fa408c877facad81e27eee3e759520b31/3F1227C0-7373-4B26-BADB-05F279D75A62.png -------------------------------------------------------------------------------- /3F695A74-EC6B-4436-9063-9A618A8CC0B8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisgrieser/alfred-docs-searches/f0f9f41fa408c877facad81e27eee3e759520b31/3F695A74-EC6B-4436-9063-9A618A8CC0B8.png -------------------------------------------------------------------------------- /582225D7-8F6C-468C-A212-86ACFA5F026C.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisgrieser/alfred-docs-searches/f0f9f41fa408c877facad81e27eee3e759520b31/582225D7-8F6C-468C-A212-86ACFA5F026C.png -------------------------------------------------------------------------------- /5A2D4239-FC30-482F-831B-D2E261B44B7F.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisgrieser/alfred-docs-searches/f0f9f41fa408c877facad81e27eee3e759520b31/5A2D4239-FC30-482F-831B-D2E261B44B7F.png -------------------------------------------------------------------------------- /5D0C789F-E59F-4435-8AB1-84CBA3CF65DC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisgrieser/alfred-docs-searches/f0f9f41fa408c877facad81e27eee3e759520b31/5D0C789F-E59F-4435-8AB1-84CBA3CF65DC.png -------------------------------------------------------------------------------- /71F9A459-55CC-41D5-A1FA-4424B696D4E3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisgrieser/alfred-docs-searches/f0f9f41fa408c877facad81e27eee3e759520b31/71F9A459-55CC-41D5-A1FA-4424B696D4E3.png -------------------------------------------------------------------------------- /807968C5-83D0-4F80-8188-636A8D536DBE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisgrieser/alfred-docs-searches/f0f9f41fa408c877facad81e27eee3e759520b31/807968C5-83D0-4F80-8188-636A8D536DBE.png -------------------------------------------------------------------------------- /A89D07AD-BB4E-4D63-B7B7-DDB763334AEC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisgrieser/alfred-docs-searches/f0f9f41fa408c877facad81e27eee3e759520b31/A89D07AD-BB4E-4D63-B7B7-DDB763334AEC.png -------------------------------------------------------------------------------- /BE9F5DBB-FD56-4FB5-8D27-682A7E1D3BFA.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisgrieser/alfred-docs-searches/f0f9f41fa408c877facad81e27eee3e759520b31/BE9F5DBB-FD56-4FB5-8D27-682A7E1D3BFA.png -------------------------------------------------------------------------------- /E0497D01-2949-468B-B5C6-D6837344A30B.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisgrieser/alfred-docs-searches/f0f9f41fa408c877facad81e27eee3e759520b31/E0497D01-2949-468B-B5C6-D6837344A30B.png -------------------------------------------------------------------------------- /FC4A9CCB-0458-42DE-9CFE-4110B7E0CADF.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisgrieser/alfred-docs-searches/f0f9f41fa408c877facad81e27eee3e759520b31/FC4A9CCB-0458-42DE-9CFE-4110B7E0CADF.png -------------------------------------------------------------------------------- /Justfile: -------------------------------------------------------------------------------- 1 | set quiet := true 2 | 3 | # REQUIRED local workflow uses same folder name 4 | 5 | workflow_uid := `basename "$PWD"` 6 | prefs_location := `defaults read com.runningwithcrayons.Alfred-Preferences syncfolder | sed "s|^~|$HOME|"` 7 | local_workflow := prefs_location / "Alfred.alfredpreferences/workflows" / workflow_uid 8 | 9 | #─────────────────────────────────────────────────────────────────────────────── 10 | 11 | transfer-changes-FROM-local: 12 | #!/usr/bin/env zsh 13 | rsync --archive --delete --exclude-from="$PWD/.rsync-exclude" "{{ local_workflow }}/" "$PWD" 14 | git status --short 15 | 16 | transfer-changes-TO-local: 17 | #!/usr/bin/env zsh 18 | rsync --archive --delete --exclude-from="$PWD/.rsync-exclude" "$PWD/" "{{ local_workflow }}" 19 | cd "{{ local_workflow }}" 20 | print "\e[1;34mChanges at the local workflow:\e[0m" 21 | git status --short . 22 | 23 | [macos] 24 | open-local-workflow-in-alfred: 25 | #!/usr/bin/env zsh 26 | # using JXA and URI for redundancy, as both are not 100 % reliable https://www.alfredforum.com/topic/18390-get-currently-edited-workflow-uri/ 27 | open "alfredpreferences://navigateto/workflows>workflow>{{ workflow_uid }}" 28 | osascript -e 'tell application id "com.runningwithcrayons.Alfred" to reveal workflow "{{ workflow_uid }}"' 29 | 30 | release: 31 | ./.build-and-release.sh 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Christopher Grieser 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Search ALL the docs 2 | ![GitHub downloads](https://img.shields.io/github/downloads/chrisgrieser/alfred-docs-searches/total?label=GitHub%20Downloads&style=plastic&logo=github) 3 | ![Alfred gallery downloads](https://img.shields.io/badge/dynamic/yaml?url=https%3A%2F%2Fraw.githubusercontent.com%2Fchrisgrieser%2F.config%2Frefs%2Fheads%2Fmain%2FAlfred.alfredpreferences%2Falfred-workflow-download-count.yaml&query=alfred-docs-searches&style=plastic&logo=alfred&label=Gallery%20Downloads&color=%235C1F87) 4 | ![Latest release](https://img.shields.io/github/v/release/chrisgrieser/alfred-docs-searches?label=Latest%20Release&style=plastic) 5 | 6 | Search hundreds of documentation sites from DevDocs and other sources via 7 | Alfred. [Recommended by the Alfred team.](https://www.alfredapp.com/blog/tips-and-tricks/workflows-for-design-and-development/) 8 | 9 | Showcase 10 | 11 | ## Table of Contents 12 | 13 | 14 | 15 | - [Installation](#installation) 16 | - [DevDocs](#devdocs) 17 | * [Usage](#usage) 18 | * [Pinning specific versions](#pinning-specific-versions) 19 | * [Icons](#icons) 20 | - [Extras](#extras) 21 | * [Documentation sites](#documentation-sites) 22 | * [Utilities](#utilities) 23 | - [Reload caches](#reload-caches) 24 | - [Maintenance notes](#maintenance-notes) 25 | - [About the developer](#about-the-developer) 26 | 27 | 28 | 29 | ## Installation 30 | [➡️ Download the latest release.](https://github.com/chrisgrieser/alfred-docs-searches/releases/latest) 31 | 32 | ## DevDocs 33 | Enable the devdocs you want to use in the workflow configuration. The 34 | enabled devdocs are searched by using the name as keyword, for example `haskell 35 | foobar` to search the Haskell DevDocs for "foobar." 36 | 37 | A few common languages have aliases (shorter keywords) noted in the popup 38 | selection, such as 39 | 40 | `js` for JavaScript. In this case, you use `js foobar` to search instead. 41 | 42 | ### Usage 43 | - : Open the documentation site. 44 | - : Copy the URL of the documentation site to the clipboard. 45 | - : Copy the entry's text to the clipboard. 46 | 47 | ### Pinning specific versions 48 | 1. In the workflow configuration, go to the `pinned devdocs versions` section. 49 | (Depending on your screen height, you might need to scroll down.) 50 | 2. The versions available are listed under the key `slug` in [this json 51 | file](https://devdocs.io/docs.json). 52 | 3. The replacements take the form `alfred_keyword:pinned_version`, one version 53 | change per line. For example, to pin the `node` and `python` use: 54 | 55 | ```txt 56 | node:node~18_lts 57 | ``` 58 | 59 | ```txt 60 | py:python~3.11 61 | ``` 62 | 63 | 4. Afterward, reload the caches via the Alfred keyword `:docs-reload` to ensure 64 | the new versions are used. 65 | 66 | ### Icons 67 | Search icons for specific documentation sites are provided by adding a file to 68 | the directory `./devdocs/icons/{keyword}.png`. PRs are welcome. 69 | 70 | ## Extras 71 | 72 | ### Documentation sites 73 | - `biome`: biome docs & rules 74 | - `ruff`: ruff docs & rules 75 | - `sc`: shellcheck wiki 76 | - `pandoc`: pandoc user manual 77 | - `wt`: WezTerm docs 78 | - `yq`: yq docs 79 | - `oh`: Obsidian help 80 | - `odd`: Obsidian developer docs 81 | - `ddg`: DuckDuckGo help pages 82 | 83 | ### Utilities 84 | - `color`: named CSS colors 85 | - `keycode`: macOS key codes 86 | * : Copy key code 87 | * : Copy AppleScript 88 | - `appid`: app-id of installed macOS apps 89 | - `win`: window information for the frontmost app 90 | - `http`: HTTP status codes 91 | - `as`: AppleScript Dictionaries of installed apps 92 | - `sound`: macOS System Sounds 93 | * : Preview (technically: Pre-listen) 94 | * : Copy sound path 95 | - Get the Uniform Type Identifier (UTI) of a selected file via the [Universal 96 | Action](https://www.alfredapp.com/help/workflows/triggers/universal-actions/). 97 | 98 | ## Reload caches 99 | In case of a recent change to a documentation site, you can manually trigger 100 | refreshing the cache via the Alfred keyword `:docs-reload`. 101 | 102 | ## Maintenance notes 103 | 1. **Remote**: Twice per month, a [GitHub 104 | Action](./.github/workflows/update-devdocs.yml) is run that checks for 105 | devdocs updates. If updates are found, the 106 | [keyword-slug-map](./.github/caches/devdocs-keyword-slug-map.json) available 107 | on this GitHub remote is updated. The `info.plist` is also updated in case 108 | not only a new version, but an entirely new documentation site becomes 109 | available. 110 | 2. **Local**: Every week, the locally available workflow fetches an update from 111 | the `keymap-slug-map` and the `info.plist` files from the GitHub remote. The 112 | update to the `info.plist` is required, so that newly available documentation 113 | sites also show up in the dropdown menus of the workflow configuration. 114 | 3. This means that any devdocs update is available to the user at most after 115 | three weeks. (The local cache can be manually updated via the Alfred keyword 116 | via `:docs-reload` to remove the seven-day delay.) 117 | 4. The purpose of this setup is to fully automate the process of making devdocs 118 | updates available to the user without requiring manual action. Furthermore, 119 | no separate release of the workflow is required. 120 | 121 | ## About the developer 122 | In my day job, I am a sociologist studying the social mechanisms underlying the 123 | digital economy. For my PhD project, I investigate the governance of the app 124 | economy and how software ecosystems manage the tension between innovation and 125 | compatibility. If you are interested in this subject, feel free to get in touch. 126 | 127 | - [Website](https://chris-grieser.de/) 128 | - [Mastodon](https://pkm.social/@pseudometa) 129 | - [ResearchGate](https://www.researchgate.net/profile/Christopher-Grieser) 130 | - [LinkedIn](https://www.linkedin.com/in/christopher-grieser-ba693b17a/) 131 | 132 | Buy Me a Coffee at ko-fi.com 135 | -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisgrieser/alfred-docs-searches/f0f9f41fa408c877facad81e27eee3e759520b31/icon.png -------------------------------------------------------------------------------- /scripts/devdocs/icons/README.md: -------------------------------------------------------------------------------- 1 | # Adding Icons 2 | - New icons are automatically picked up by Alfred by adding files to this folder. 3 | - The files must be named after the workflow **keyword**, for example `py` for 4 | python. 5 | -------------------------------------------------------------------------------- /scripts/devdocs/icons/bash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisgrieser/alfred-docs-searches/f0f9f41fa408c877facad81e27eee3e759520b31/scripts/devdocs/icons/bash.png -------------------------------------------------------------------------------- /scripts/devdocs/icons/cani.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisgrieser/alfred-docs-searches/f0f9f41fa408c877facad81e27eee3e759520b31/scripts/devdocs/icons/cani.png -------------------------------------------------------------------------------- /scripts/devdocs/icons/css.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisgrieser/alfred-docs-searches/f0f9f41fa408c877facad81e27eee3e759520b31/scripts/devdocs/icons/css.png -------------------------------------------------------------------------------- /scripts/devdocs/icons/dom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisgrieser/alfred-docs-searches/f0f9f41fa408c877facad81e27eee3e759520b31/scripts/devdocs/icons/dom.png -------------------------------------------------------------------------------- /scripts/devdocs/icons/electron.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisgrieser/alfred-docs-searches/f0f9f41fa408c877facad81e27eee3e759520b31/scripts/devdocs/icons/electron.png -------------------------------------------------------------------------------- /scripts/devdocs/icons/esbuild.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisgrieser/alfred-docs-searches/f0f9f41fa408c877facad81e27eee3e759520b31/scripts/devdocs/icons/esbuild.png -------------------------------------------------------------------------------- /scripts/devdocs/icons/git.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisgrieser/alfred-docs-searches/f0f9f41fa408c877facad81e27eee3e759520b31/scripts/devdocs/icons/git.png -------------------------------------------------------------------------------- /scripts/devdocs/icons/hs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisgrieser/alfred-docs-searches/f0f9f41fa408c877facad81e27eee3e759520b31/scripts/devdocs/icons/hs.png -------------------------------------------------------------------------------- /scripts/devdocs/icons/html.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisgrieser/alfred-docs-searches/f0f9f41fa408c877facad81e27eee3e759520b31/scripts/devdocs/icons/html.png -------------------------------------------------------------------------------- /scripts/devdocs/icons/jq.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisgrieser/alfred-docs-searches/f0f9f41fa408c877facad81e27eee3e759520b31/scripts/devdocs/icons/jq.png -------------------------------------------------------------------------------- /scripts/devdocs/icons/js.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisgrieser/alfred-docs-searches/f0f9f41fa408c877facad81e27eee3e759520b31/scripts/devdocs/icons/js.png -------------------------------------------------------------------------------- /scripts/devdocs/icons/jsdoc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisgrieser/alfred-docs-searches/f0f9f41fa408c877facad81e27eee3e759520b31/scripts/devdocs/icons/jsdoc.png -------------------------------------------------------------------------------- /scripts/devdocs/icons/lua.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisgrieser/alfred-docs-searches/f0f9f41fa408c877facad81e27eee3e759520b31/scripts/devdocs/icons/lua.png -------------------------------------------------------------------------------- /scripts/devdocs/icons/man.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisgrieser/alfred-docs-searches/f0f9f41fa408c877facad81e27eee3e759520b31/scripts/devdocs/icons/man.png -------------------------------------------------------------------------------- /scripts/devdocs/icons/mt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisgrieser/alfred-docs-searches/f0f9f41fa408c877facad81e27eee3e759520b31/scripts/devdocs/icons/mt.png -------------------------------------------------------------------------------- /scripts/devdocs/icons/node.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisgrieser/alfred-docs-searches/f0f9f41fa408c877facad81e27eee3e759520b31/scripts/devdocs/icons/node.png -------------------------------------------------------------------------------- /scripts/devdocs/icons/np.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisgrieser/alfred-docs-searches/f0f9f41fa408c877facad81e27eee3e759520b31/scripts/devdocs/icons/np.png -------------------------------------------------------------------------------- /scripts/devdocs/icons/npm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisgrieser/alfred-docs-searches/f0f9f41fa408c877facad81e27eee3e759520b31/scripts/devdocs/icons/npm.png -------------------------------------------------------------------------------- /scripts/devdocs/icons/pd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisgrieser/alfred-docs-searches/f0f9f41fa408c877facad81e27eee3e759520b31/scripts/devdocs/icons/pd.png -------------------------------------------------------------------------------- /scripts/devdocs/icons/py.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisgrieser/alfred-docs-searches/f0f9f41fa408c877facad81e27eee3e759520b31/scripts/devdocs/icons/py.png -------------------------------------------------------------------------------- /scripts/devdocs/icons/ts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisgrieser/alfred-docs-searches/f0f9f41fa408c877facad81e27eee3e759520b31/scripts/devdocs/icons/ts.png -------------------------------------------------------------------------------- /scripts/devdocs/open-at-original-site.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env osascript -l JavaScript 2 | ObjC.import("stdlib"); 3 | const app = Application.currentApplication(); 4 | app.includeStandardAdditions = true; 5 | //────────────────────────────────────────────────────────────────────────────── 6 | 7 | /** @type {Record} */ 8 | const originalSites = { 9 | css: "https://developer.mozilla.org/en-US/docs/Web/CSS/", 10 | javascript: "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/", 11 | html: "https://developer.mozilla.org/en-US/docs/Web/HTML/", 12 | dom: "https://developer.mozilla.org/en-US/docs/Web/API/", 13 | jsdoc: "https://jsdoc.app/", 14 | typescript: "https://www.typescriptlang.org/", 15 | electron: "https://www.electronjs.org/docs/latest/", 16 | python: "https://docs.python.org/{{version}}/", 17 | git: "https://git-scm.com/docs/", 18 | lua: "https://www.lua.org/manual/{{version}}/manual.html", 19 | hammerspoon: "https://www.hammerspoon.org/docs/", 20 | // biome-ignore lint/style/useNamingConvention: not by me 21 | browser_support_tables: "https://caniuse.com/", 22 | node: "https://nodejs.org/api/", 23 | moment: "https://momentjs.com/docs/#/", 24 | npm: "https://docs.npmjs.com/", 25 | esbuild: "https://esbuild.github.io/", 26 | }; 27 | 28 | //────────────────────────────────────────────────────────────────────────────── 29 | 30 | /** @type {AlfredRun} */ 31 | // biome-ignore lint/correctness/noUnusedVariables: Alfred run 32 | function run(argv) { 33 | const url = argv[0]; 34 | let [_, topic, version, site] = url.match(/.*devdocs\.io\/([^/~]*)(?:~(.*?))?\/(.+)/) || []; 35 | let sourcePage = originalSites[topic]; 36 | const useSourcePageIfAvailable = $.getenv("use_source_page_if_available") === "1"; 37 | 38 | // OPEN ON DEVDOCS 39 | if (!(useSourcePageIfAvailable && sourcePage)) { 40 | app.openLocation(url); 41 | return; 42 | } 43 | 44 | // OPEN AT ORIIGNAL 45 | if (version) sourcePage = sourcePage.replace("{{version}}", version); 46 | 47 | // a bunch of annoying special cases… 48 | if (topic === "lua") site = site.replace("index", ""); 49 | if (topic === "node") site = site.replace("#", ".html#"); 50 | if (topic === "moment") site = site.replace("index#/", ""); 51 | 52 | const sourceUrl = sourcePage + site; 53 | app.openLocation(sourceUrl); 54 | } 55 | -------------------------------------------------------------------------------- /scripts/devdocs/search-devdocs.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env osascript -l JavaScript 2 | ObjC.import("stdlib"); 3 | const app = Application.currentApplication(); 4 | app.includeStandardAdditions = true; 5 | //────────────────────────────────────────────────────────────────────────────── 6 | 7 | // INFO 8 | // All available languages: https://devdocs.io/docs.json 9 | // Search Index: https://documents.devdocs.io/javascript/index.json 10 | // Data: https://documents.devdocs.io/javascript/db.json 11 | // However, all these seem undocumented. (source: https://github.com/luckasRanarison/nvim-devdocs) 12 | 13 | /** @typedef {Object} DevDocsIndex 14 | * @property {{name: string, path: string, type: string}[]} entries 15 | * @property {{name: string, count: number, slug: string}[]} types 16 | */ 17 | 18 | //────────────────────────────────────────────────────────────────────────────── 19 | 20 | /** @param {string} url @return {string} */ 21 | function httpRequest(url) { 22 | const queryURL = $.NSURL.URLWithString(url); 23 | const data = $.NSData.dataWithContentsOfURL(queryURL); 24 | return $.NSString.alloc.initWithDataEncoding(data, $.NSUTF8StringEncoding).js; 25 | } 26 | 27 | /** @param {string} str */ 28 | function camelCaseMatch(str) { 29 | const subwords = str.replace(/[-_./]/g, " "); 30 | const fullword = str.replace(/[-_./]/g, ""); 31 | const camelCaseSeparated = str.replace(/([A-Z])/g, " $1"); 32 | return [subwords, camelCaseSeparated, fullword, str].join(" ") + " "; 33 | } 34 | 35 | const fileExists = (/** @type {string} */ filePath) => Application("Finder").exists(Path(filePath)); 36 | 37 | function ensureCacheFolderExists() { 38 | const finder = Application("Finder"); 39 | const cacheDir = $.getenv("alfred_workflow_cache"); 40 | if (!finder.exists(Path(cacheDir))) { 41 | // biome-ignore lint/suspicious/noConsole: intentional 42 | console.log("Cache Dir does not exist and is created."); 43 | const cacheDirBasename = $.getenv("alfred_workflow_bundleid"); 44 | const cacheDirParent = cacheDir.slice(0, -cacheDirBasename.length); 45 | finder.make({ 46 | new: "folder", 47 | at: Path(cacheDirParent), 48 | withProperties: { name: cacheDirBasename }, 49 | }); 50 | } 51 | } 52 | 53 | /** @param {string} path */ 54 | function cacheIsOutdated(path) { 55 | const cacheAgeThresholdDays = 7; // CONFIG 56 | const cacheObj = Application("System Events").aliases[path]; 57 | if (!cacheObj.exists()) return true; 58 | const cacheAgeDays = (Date.now() - +cacheObj.creationDate()) / 1000 / 60 / 60 / 24; 59 | return cacheAgeDays > cacheAgeThresholdDays; 60 | } 61 | 62 | /** @param {string} filepath @param {string} text */ 63 | function writeToFile(filepath, text) { 64 | const str = $.NSString.alloc.initWithUTF8String(text); 65 | str.writeToFileAtomicallyEncodingError(filepath, true, $.NSUTF8StringEncoding, null); 66 | } 67 | 68 | /** @param {string} path */ 69 | function readFile(path) { 70 | const data = $.NSFileManager.defaultManager.contentsAtPath(path); 71 | const str = $.NSString.alloc.initWithDataEncoding(data, $.NSUTF8StringEncoding); 72 | return ObjC.unwrap(str); 73 | } 74 | 75 | //────────────────────────────────────────────────────────────────────────────── 76 | 77 | // biome-ignore lint/correctness/noUnusedVariables: Alfred run 78 | function run() { 79 | const prefix = $.getenv("shared_devdocs_prefix"); 80 | const keyword = $.getenv("alfred_workflow_keyword").substring(prefix.length); 81 | 82 | // biome-ignore lint/suspicious/noConsole: intentional 83 | console.log("keyword:", keyword); 84 | 85 | ensureCacheFolderExists(); 86 | const mapCache = $.getenv("alfred_workflow_cache") + "/keyword-slug-map.json"; 87 | if (cacheIsOutdated(mapCache)) { 88 | const tree = "https://raw.githubusercontent.com/chrisgrieser/alfred-docs-searches/main"; 89 | 90 | const mapUrl = tree + "/.github/caches/devdocs-keyword-slug-map.json"; 91 | writeToFile(mapCache, httpRequest(mapUrl)); 92 | 93 | // INFO self-update this workflow's `info.plist` to include newly 94 | // available devdocs in the workflow configuration's selectors 95 | const remoteInfoPlist = tree + "/info.plist"; 96 | writeToFile("./info.plist", httpRequest(remoteInfoPlist)); 97 | } 98 | 99 | const keywordLanguageMap = JSON.parse(readFile(mapCache)); 100 | let languageSlug = keywordLanguageMap[keyword]; 101 | 102 | // PINNED VERSIONS 103 | const pinnedVersions = $.getenv("select_versions") 104 | .split("\n") 105 | .filter((line) => line.trim() !== "") 106 | .map((line) => { 107 | const [usedVersion, pinnedVersion] = line.split(":"); 108 | return { used: usedVersion.trim(), pinned: pinnedVersion.trim() }; 109 | }); 110 | const replacement = pinnedVersions.find((version) => version.used === keyword); 111 | if (replacement) { 112 | // biome-ignore lint/suspicious/noConsole: intentional 113 | console.log("Pinned version found."); 114 | languageSlug = replacement.pinned; 115 | } 116 | 117 | //─────────────────────────────────────────────────────────────────────────── 118 | 119 | // INFO using custom cache mechanism, since Alfred's cache does not work with 120 | // multiple keywords: https://www.alfredforum.com/topic/21754-wrong-alfred-55-cache-used-when-using-alternate-keywords-like-foobar/#comment-113358 121 | const langIndexCache = `${$.getenv("alfred_workflow_cache")}/${languageSlug}.json`; 122 | 123 | if (cacheIsOutdated(langIndexCache)) { 124 | const iconpath = `./scripts/devdocs/icons/${keyword}.png`; 125 | const iconExists = fileExists(iconpath); 126 | 127 | const indexUrl = `https://documents.devdocs.io/${languageSlug}/index.json`; 128 | // biome-ignore lint/suspicious/noConsole: intentional 129 | console.log("indexUrl:", indexUrl); 130 | 131 | /** @type {DevDocsIndex} */ 132 | const response = JSON.parse(httpRequest(indexUrl)); 133 | 134 | const entries = response.entries.map((entry) => { 135 | const url = `https://devdocs.io/${languageSlug}/${entry.path}`; 136 | 137 | /** @type{AlfredItem} */ 138 | const item = { 139 | title: entry.name, 140 | subtitle: entry.type, 141 | match: camelCaseMatch(entry.name), 142 | quicklookurl: url, 143 | arg: url, 144 | mods: { 145 | cmd: { arg: entry.name }, // copy entry 146 | }, 147 | uid: url, 148 | }; 149 | if (iconExists) item.icon = { path: iconpath }; // icon defaults to devdocs icon 150 | return item; 151 | }); 152 | 153 | writeToFile(langIndexCache, JSON.stringify({ items: entries })); 154 | } 155 | 156 | return readFile(langIndexCache); 157 | } 158 | -------------------------------------------------------------------------------- /scripts/devdocs/update-devdocs.mjs: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | //────────────────────────────────────────────────────────────────────────────── 3 | // INFO 4 | // - needs to be run from repo root: `node ./scripts/devdocs/update-devdocs.mjs` 5 | // - updates which devdocs are available, and also the versions of devdocs 6 | // (automatically switches to the latest version) 7 | // - WARN this overwrites all available workflow configuration, so changes to 8 | // the workflow configuration need to be added here manually, such as the 9 | // field for using specific devdocs versions. 10 | //────────────────────────────────────────────────────────────────────────────── 11 | import fs from "node:fs"; 12 | 13 | /** @type {Record} */ 14 | const customAliases = { 15 | hammerspoon: "hs", 16 | // biome-ignore lint/style/useNamingConvention: not set by me 17 | browser_support_tables: "cani", 18 | matplotlib: "plt", // preferring the conventional `plt` over `mlp` https://docs.astral.sh/ruff/settings/#lint_flake8-import-conventions_aliases 19 | }; 20 | 21 | // IMPORTANT extra lines for pinned workflow versions and opening at original 22 | // page, since it's overridden otherwise 23 | const extraWorkflowConfig = [ 24 | " config default required trim verticalsize 3 description one per line; see to the right for explanations label pinned devdocs versions type textarea variable select_versions ", 25 | " config default required text description Only available for a few sites. PRs welcome. label open at original type checkbox variable use_source_page_if_available ", 26 | ' config default placeholder required trim description Shared keyword prefix for DevDocs searches. If set to "dd" , will search the bash documentation via "ddbash" instead of "bash". Leave empty to not use any such prefix. label DevDocs prefix type textfield variable shared_devdocs_prefix ', 27 | ]; 28 | 29 | //────────────────────────────────────────────────────────────────────────────── 30 | 31 | async function run() { 32 | // alternative: https://documents.devdocs.io/docs.json 33 | const response = await fetch("https://devdocs.io/docs.json"); 34 | const json = await response.json(); 35 | 36 | /** @type {Record} */ 37 | const allLangs = {}; 38 | const noneItem = " ----- "; 39 | const infoPlistPopup = [noneItem]; 40 | for (const lang of json) { 41 | const id = lang.slug.replace(/~.*/, ""); // remove version suffix 42 | const keyword = customAliases[id] || lang.alias || id; // custom -> devdocs -> id 43 | 44 | // skip duplicates 45 | // (assuming the JSON puts newer version on top, skips older versions) 46 | if (allLangs[keyword]) continue; 47 | allLangs[keyword] = lang.slug; 48 | 49 | // xml -> info.plist 50 | const label = keyword !== id ? `${id} (keyword: ${keyword})` : id; 51 | const line = ` ${label} ${keyword} `; 52 | infoPlistPopup.push(line); 53 | } 54 | 55 | // keyword-slug-map 56 | if (!fs.existsSync("./.github/caches/")) fs.mkdirSync("./.github/caches/", { recursive: true }); 57 | const beautifiedForBetterDiff = JSON.stringify(allLangs, null, 2); 58 | fs.writeFileSync("./.github/caches/devdocs-keyword-slug-map.json", beautifiedForBetterDiff); 59 | 60 | // info.plist: update to insert all languages as options 61 | /** @type {string[]} */ 62 | const xmlLines = fs.readFileSync("./info.plist", "utf8").split("\n"); 63 | 64 | // create multiple popups to select in Alfred config 65 | const numberOfPopups = 40; 66 | 67 | /** @type {string[]} */ 68 | const newXmlLines = []; 69 | for (let i = 1; i <= numberOfPopups; i++) { 70 | const label = i === 1 ? "Enabled devdocs" : ""; 71 | const number = i.toString().padStart(2, "0"); 72 | 73 | newXmlLines.push( 74 | " config default pairs ", 75 | ...infoPlistPopup, 76 | ` description label ${label} type popupbutton variable keyword_${number} `, 77 | ); 78 | } 79 | newXmlLines.push(...extraWorkflowConfig); 80 | 81 | const start = xmlLines.indexOf("\tuserconfigurationconfig") + 2; 82 | const end = xmlLines.indexOf("\t", start); 83 | xmlLines.splice(start, end - start, ...newXmlLines); 84 | fs.writeFileSync("./info.plist", xmlLines.join("\n")); 85 | } 86 | 87 | await run(); 88 | -------------------------------------------------------------------------------- /scripts/extra-utilities/.ignore: -------------------------------------------------------------------------------- 1 | color-svgs/* 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/appid.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env osascript -l JavaScript 2 | ObjC.import("stdlib"); 3 | const app = Application.currentApplication(); 4 | app.includeStandardAdditions = true; 5 | //────────────────────────────────────────────────────────────────────────────── 6 | 7 | /** @type {AlfredRun} */ 8 | // biome-ignore lint/correctness/noUnusedVariables: Alfred run 9 | function run() { 10 | const apps = app 11 | .doShellScript("mdfind \"kMDItemKind == 'Application'\"") 12 | .split("\r") 13 | .map((path) => { 14 | if ( 15 | !path.endsWith(".app") || 16 | (path.startsWith("/System/Library/CoreServices/") && !path.endsWith("Finder.app")) 17 | ) 18 | return {}; 19 | const appName = (path.split("/").pop() || "").slice(0, -4); 20 | return { 21 | title: appName, 22 | type: "file:skipcheck", 23 | icon: { path: path, type: "fileicon" }, 24 | arg: appName, 25 | }; 26 | }); 27 | 28 | return JSON.stringify({ 29 | items: apps, 30 | cache: { 31 | seconds: 300, // low, in case user installs new apps 32 | loosereload: true, 33 | }, 34 | }); 35 | } 36 | -------------------------------------------------------------------------------- /scripts/extra-utilities/appid.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env zsh 2 | 3 | appPath="$*" 4 | appName=$(basename "$appPath") 5 | appid=$(osascript -e "id of application \"$appName\"") 6 | 7 | echo -n "$appid" | pbcopy 8 | echo -n "$appid" # Alfred Notification 9 | -------------------------------------------------------------------------------- /scripts/extra-utilities/apple-keycodes.json: -------------------------------------------------------------------------------- 1 | { 2 | "items": [ 3 | { 4 | "title": "⎋ / Escape", 5 | "match": "escape 53", 6 | "arg": "53", 7 | "subtitle": "53", 8 | "mods": { 9 | "alt": { "arg": "key code" } 10 | } 11 | }, 12 | { 13 | "title": "⌘ / Command", 14 | "match": "command 55", 15 | "arg": "55", 16 | "subtitle": "55", 17 | "mods": { 18 | "alt": { "arg": "key code" } 19 | } 20 | }, 21 | { 22 | "title": "⌥ / Option / Alt", 23 | "match": "option alt 58", 24 | "arg": "58", 25 | "subtitle": "58 (left) / 61 (right)", 26 | "mods": { 27 | "alt": { "arg": "key code" } 28 | } 29 | }, 30 | { 31 | "title": "⌃ / Control", 32 | "match": "control 59 62", 33 | "arg": "59", 34 | "subtitle": "59 (left) / 62 (right)", 35 | "mods": { 36 | "alt": { "arg": "key code 59 -- control" } 37 | } 38 | }, 39 | { 40 | "title": "⇧ / Shift", 41 | "match": "shift 56 60", 42 | "arg": "56", 43 | "subtitle": "56 (left) / 60 (right)", 44 | "mods": { 45 | "alt": { "arg": "key code 56 -- shift" } 46 | } 47 | }, 48 | { 49 | "title": "⇪ / Caps Lock", 50 | "match": "capslock 57", 51 | "arg": "57", 52 | "subtitle": "57", 53 | "mods": { 54 | "alt": { "arg": "key code 57 -- lock" } 55 | } 56 | }, 57 | { 58 | "title": "⏎ / Return", 59 | "match": "return 36", 60 | "arg": "36", 61 | "subtitle": "36", 62 | "mods": { 63 | "alt": { "arg": "key code 36 -- return" } 64 | } 65 | }, 66 | { 67 | "title": "⌤ / Enter", 68 | "match": "enter 76", 69 | "arg": "76", 70 | "subtitle": "76", 71 | "mods": { 72 | "alt": { "arg": "key code 76 -- enter" } 73 | } 74 | }, 75 | { 76 | "title": "⇥ / Tab", 77 | "match": "tab 48", 78 | "arg": "48", 79 | "subtitle": "48", 80 | "mods": { 81 | "alt": { "arg": "key code 48 -- tab" } 82 | } 83 | }, 84 | { 85 | "title": "␣ / Space", 86 | "match": "space 49", 87 | "arg": "49", 88 | "subtitle": "49", 89 | "mods": { 90 | "alt": { "arg": "key code 49 -- space" } 91 | } 92 | }, 93 | { 94 | "title": "⌫ / Delete / Backspace", 95 | "match": "delete backspace 51", 96 | "arg": "51", 97 | "subtitle": "51", 98 | "mods": { 99 | "alt": { "arg": "key code 51 -- backspace" } 100 | } 101 | }, 102 | { 103 | "title": "⌦ / Forward Delete", 104 | "match": "forward delete 117", 105 | "arg": "117", 106 | "subtitle": "117", 107 | "mods": { 108 | "alt": { "arg": "key code 117 -- delete" } 109 | } 110 | }, 111 | { 112 | "title": "← / Left Arrow", 113 | "match": "left arrow 123", 114 | "arg": "123", 115 | "subtitle": "123", 116 | "mods": { 117 | "alt": { "arg": "key code 123 -- arrow" } 118 | } 119 | }, 120 | { 121 | "title": "→ / Right Arrow", 122 | "match": "right arrow 124", 123 | "arg": "124", 124 | "subtitle": "124", 125 | "mods": { 126 | "alt": { "arg": "key code 124 -- arrow" } 127 | } 128 | }, 129 | { 130 | "title": "↓ / Down Arrow", 131 | "match": "down arrow 125", 132 | "arg": "125", 133 | "subtitle": "125", 134 | "mods": { 135 | "alt": { "arg": "key code 125 -- arrow" } 136 | } 137 | }, 138 | { 139 | "title": "↑ / Up Arrow", 140 | "match": "up arrow 126", 141 | "arg": "126", 142 | "subtitle": "126", 143 | "mods": { 144 | "alt": { "arg": "key code 126 -- arrow" } 145 | } 146 | }, 147 | { 148 | "title": "⇞ / Page Up", 149 | "match": "pageup up 116", 150 | "arg": "116", 151 | "subtitle": "116", 152 | "mods": { 153 | "alt": { "arg": "key code 116 -- up" } 154 | } 155 | }, 156 | { 157 | "title": "⇟ / Page Down", 158 | "match": "pageup down 121", 159 | "arg": "121", 160 | "subtitle": "121", 161 | "mods": { 162 | "alt": { "arg": "key code 121 -- down" } 163 | } 164 | }, 165 | { 166 | "title": "⇱ / Home", 167 | "match": "home 115", 168 | "arg": "115", 169 | "subtitle": "115", 170 | "mods": { 171 | "alt": { "arg": "key code 115 -- home" } 172 | } 173 | }, 174 | { 175 | "title": "⇲ / End", 176 | "match": "end 119", 177 | "arg": "119", 178 | "subtitle": "119", 179 | "mods": { 180 | "alt": { "arg": "key code 119 -- end" } 181 | } 182 | }, 183 | { 184 | "title": "fn", 185 | "match": "fn 63", 186 | "arg": "63", 187 | "subtitle": "63", 188 | "mods": { 189 | "alt": { "arg": "key code 63 -- Fn" } 190 | } 191 | }, 192 | { 193 | "title": "F1", 194 | "match": "f1 122", 195 | "arg": "122", 196 | "subtitle": "122", 197 | "mods": { 198 | "alt": { "arg": "key code 122 +- F1" } 199 | } 200 | }, 201 | { 202 | "title": "F2", 203 | "match": "f2 120", 204 | "arg": "120", 205 | "subtitle": "120", 206 | "mods": { 207 | "alt": { "arg": "key code 120 +- F2" } 208 | } 209 | }, 210 | { 211 | "title": "F3", 212 | "match": "f3 99", 213 | "arg": "99", 214 | "subtitle": "99", 215 | "mods": { 216 | "alt": { "arg": "key code 99 +- F3" } 217 | } 218 | }, 219 | { 220 | "title": "F4", 221 | "match": "f4 118", 222 | "arg": "118", 223 | "subtitle": "118", 224 | "mods": { 225 | "alt": { "arg": "key code 118 +- F4" } 226 | } 227 | }, 228 | { 229 | "title": "F5", 230 | "match": "f5 96", 231 | "arg": "96", 232 | "subtitle": "96", 233 | "mods": { 234 | "alt": { "arg": "key code 96 +- F5" } 235 | } 236 | }, 237 | { 238 | "title": "F6", 239 | "match": "f6 97", 240 | "arg": "97", 241 | "subtitle": "97", 242 | "mods": { 243 | "alt": { "arg": "key code 97 +- F6" } 244 | } 245 | }, 246 | { 247 | "title": "F7", 248 | "match": "f7 98", 249 | "arg": "98", 250 | "subtitle": "98", 251 | "mods": { 252 | "alt": { "arg": "key code 98 +- F7" } 253 | } 254 | }, 255 | { 256 | "title": "F8", 257 | "match": "f8 100", 258 | "arg": "100", 259 | "subtitle": "100", 260 | "mods": { 261 | "alt": { "arg": "key code 100 +- F8" } 262 | } 263 | }, 264 | { 265 | "title": "F9", 266 | "match": "f9 101", 267 | "arg": "101", 268 | "subtitle": "101", 269 | "mods": { 270 | "alt": { "arg": "key code 101 +- F9" } 271 | } 272 | }, 273 | { 274 | "title": "F10", 275 | "match": "f10 109", 276 | "arg": "109", 277 | "subtitle": "109", 278 | "mods": { 279 | "alt": { "arg": "key code 109 -- F10" } 280 | } 281 | }, 282 | { 283 | "title": "F11", 284 | "match": "f11 103", 285 | "arg": "103", 286 | "subtitle": "103", 287 | "mods": { 288 | "alt": { "arg": "key code 103 -- F11" } 289 | } 290 | }, 291 | { 292 | "title": "F12", 293 | "match": "f12 111", 294 | "arg": "111", 295 | "subtitle": "111", 296 | "mods": { 297 | "alt": { "arg": "key code 111 -- F12" } 298 | } 299 | }, 300 | { 301 | "title": "F13", 302 | "match": "f13 105", 303 | "arg": "105", 304 | "subtitle": "105", 305 | "mods": { 306 | "alt": { "arg": "key code 105 -- F13" } 307 | } 308 | }, 309 | { 310 | "title": "F14", 311 | "match": "f14 107", 312 | "arg": "107", 313 | "subtitle": "107", 314 | "mods": { 315 | "alt": { "arg": "key code 107 -- F14" } 316 | } 317 | }, 318 | { 319 | "title": "F15", 320 | "match": "f15 113", 321 | "arg": "113", 322 | "subtitle": "113", 323 | "mods": { 324 | "alt": { "arg": "key code 113 -- F15" } 325 | } 326 | }, 327 | { 328 | "title": "F16", 329 | "match": "f16 106", 330 | "arg": "106", 331 | "subtitle": "106", 332 | "mods": { 333 | "alt": { "arg": "key code 106 -- F16" } 334 | } 335 | }, 336 | { 337 | "title": "F17", 338 | "match": "f17 64", 339 | "arg": "64", 340 | "subtitle": "64", 341 | "mods": { 342 | "alt": { "arg": "key code 64 -- F17" } 343 | } 344 | }, 345 | { 346 | "title": "F18", 347 | "match": "f18 79", 348 | "arg": "79", 349 | "subtitle": "79", 350 | "mods": { 351 | "alt": { "arg": "key code 79 -- F18" } 352 | } 353 | }, 354 | { 355 | "title": "F19", 356 | "match": "f19 80", 357 | "arg": "80", 358 | "subtitle": "80", 359 | "mods": { 360 | "alt": { "arg": "key code 80 -- F19" } 361 | } 362 | }, 363 | { 364 | "title": "F20", 365 | "match": "f20 90", 366 | "arg": "90", 367 | "subtitle": "90", 368 | "mods": { 369 | "alt": { "arg": "key code 90 -- F20" } 370 | } 371 | } 372 | ] 373 | } 374 | -------------------------------------------------------------------------------- /scripts/extra-utilities/applescript-dictionaries.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env osascript -l JavaScript 2 | ObjC.import("stdlib"); 3 | const app = Application.currentApplication(); 4 | app.includeStandardAdditions = true; 5 | //────────────────────────────────────────────────────────────────────────────── 6 | 7 | // biome-ignore lint/correctness/noUnusedVariables: Alfred run 8 | function run() { 9 | /** @type AlfredItem[] */ 10 | const appsWithDict = app 11 | // Caveat: Script Editor does not have .sdef file 12 | .doShellScript(`find \ 13 | '/Applications' \ 14 | "$HOME/Applications" \ 15 | '/System/Applications' \ 16 | '/System/Library/CoreServices' \ 17 | '/System/Library/ScriptingAdditions' \ 18 | -path '*/Contents/Resources/*.sdef' -mindepth 4 -maxdepth 4 19 | `) 20 | .split("\r") 21 | .map((sdefPath) => { 22 | const appPath = sdefPath.replace(/(.*\/.*?\.(?:app|osax))\/.*\.sdef/, "$1"); 23 | const appName = appPath.replace(/.*\/(.*)\.app/, "$1"); 24 | return { 25 | title: appName, 26 | subtitle: appPath, 27 | icon: { path: appPath, type: "fileicon" }, 28 | arg: sdefPath, 29 | }; 30 | }); 31 | return JSON.stringify({ 32 | items: appsWithDict, 33 | cache: { 34 | seconds: 300, // low, in case user installs new apps 35 | loosereload: true, 36 | }, 37 | }); 38 | } 39 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/aliceblue.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/antiquewhite.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/aqua.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/aquamarine.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/azure.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/beige.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/bisque.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/black.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/blanchedalmond.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/blue.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/blueviolet.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/brown.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/burlywood.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/cadetblue.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/chartreuse.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/chocolate.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/coral.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/cornflowerblue.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/cornsilk.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/crimson.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/cyan.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/darkblue.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/darkcyan.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/darkgoldenrod.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/darkgray.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/darkgreen.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/darkgrey.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/darkkhaki.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/darkmagenta.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/darkolivegreen.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/darkorange.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/darkorchid.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/darkred.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/darksalmon.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/darkseagreen.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/darkslateblue.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/darkslategray.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/darkslategrey.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/darkturquoise.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/darkviolet.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/deeppink.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/deepskyblue.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/dimgray.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/dimgrey.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/dodgerblue.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/firebrick.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/floralwhite.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/forestgreen.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/fuchsia.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/gainsboro.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/ghostwhite.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/gold.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/goldenrod.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/gray.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/green.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/greenyellow.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/grey.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/honeydew.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/hotpink.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/indianred.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/indigo.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/ivory.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/khaki.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/lavender.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/lavenderblush.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/lawngreen.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/lemonchiffon.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/lightblue.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/lightcoral.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/lightcyan.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/lightgoldenrodyellow.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/lightgray.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/lightgreen.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/lightgrey.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/lightpink.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/lightsalmon.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/lightseagreen.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/lightskyblue.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/lightslategray.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/lightslategrey.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/lightsteelblue.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/lightyellow.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/lime.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/limegreen.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/linen.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/magenta.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/maroon.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/mediumaquamarine.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/mediumblue.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/mediumorchid.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/mediumpurple.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/mediumseagreen.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/mediumslateblue.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/mediumspringgreen.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/mediumturquoise.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/mediumvioletred.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/midnightblue.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/mintcream.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/mistyrose.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/moccasin.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/navajowhite.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/navy.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/oldlace.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/olive.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/olivedrab.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/orange.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/orangered.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/orchid.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/palegoldenrod.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/palegreen.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/paleturquoise.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/palevioletred.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/papayawhip.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/peachpuff.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/peru.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/pink.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/plum.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/powderblue.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/purple.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/rebeccapurple.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/red.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/rosybrown.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/royalblue.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/saddlebrown.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/salmon.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/sandybrown.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/seagreen.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/seashell.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/sienna.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/silver.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/skyblue.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/slateblue.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/slategray.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/slategrey.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/snow.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/springgreen.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/steelblue.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/tan.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/teal.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/thistle.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/tomato.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/turquoise.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/violet.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/wheat.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/white.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/whitesmoke.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/yellow.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/color-svgs/yellowgreen.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/extra-utilities/get-window-information.applescript: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env osascript 2 | tell application "System Events" 3 | set frontProcess to first application process whose frontmost is true 4 | set appName to the name of frontProcess # process to name 5 | end tell 6 | set appid to id of application appName # name to app to appid 7 | 8 | set br to (linefeed & linefeed) 9 | 10 | # app info 11 | set output to "# App: " & appName & br & "- **bundle id**: " & appid & br 12 | 13 | tell application "System Events" 14 | # window info 15 | set windowCount to 0 16 | tell frontProcess 17 | repeat with win in (every window) 18 | set windowCount to windowCount + 1 19 | set header to "### Window " & windowCount 20 | set win_name to "- **title**: \"" & (name of win) & "\"" 21 | set win_role to "- **role**: " & (role of win) & " (" & (subrole of win) & ")" 22 | set win_size_arr to size of win 23 | set win_size to "- **size**: " & (item 1 of win_size_arr as text) & "x" & (item 2 of win_size_arr as text) 24 | set output to output & header & br & win_name & br & win_role & br & win_size & br & br 25 | end repeat 26 | end tell 27 | end tell 28 | 29 | output -- direct return 30 | -------------------------------------------------------------------------------- /scripts/extra-utilities/http-status-codes.json: -------------------------------------------------------------------------------- 1 | { 2 | "items": [ 3 | { "title": "100 Continue" }, 4 | { "title": "101 Switching protocols" }, 5 | { "title": "102 Processing" }, 6 | { "title": "103 Early Hints" }, 7 | { "title": "200 OK" }, 8 | { "title": "201 Created" }, 9 | { "title": "202 Accepted" }, 10 | { "title": "203 Non-Authoritative Information" }, 11 | { "title": "204 No Content" }, 12 | { "title": "205 Reset Content" }, 13 | { "title": "206 Partial Content" }, 14 | { "title": "207 Multi-Status" }, 15 | { "title": "208 Already Reported" }, 16 | { "title": "226 IM Used" }, 17 | { "title": "300 Multiple Choices" }, 18 | { "title": "301 Moved Permanently" }, 19 | { "title": "302 Found (Previously \"Moved Temporarily\")" }, 20 | { "title": "303 See Other" }, 21 | { "title": "304 Not Modified" }, 22 | { "title": "305 Use Proxy" }, 23 | { "title": "306 Switch Proxy" }, 24 | { "title": "307 Temporary Redirect" }, 25 | { "title": "308 Permanent Redirect" }, 26 | { "title": "400 Bad Request" }, 27 | { "title": "401 Unauthorized" }, 28 | { "title": "402 Payment Required" }, 29 | { "title": "403 Forbidden" }, 30 | { "title": "404 Not Found" }, 31 | { "title": "405 Method Not Allowed" }, 32 | { "title": "406 Not Acceptable" }, 33 | { "title": "407 Proxy Authentication Required" }, 34 | { "title": "408 Request Timeout" }, 35 | { "title": "409 Conflict" }, 36 | { "title": "410 Gone" }, 37 | { "title": "411 Length Required" }, 38 | { "title": "412 Precondition Failed" }, 39 | { "title": "413 Payload Too Large" }, 40 | { "title": "414 URI Too Long" }, 41 | { "title": "415 Unsupported Media Type" }, 42 | { "title": "416 Range Not Satisfiable" }, 43 | { "title": "417 Expectation Failed" }, 44 | { "title": "418 I'm a Teapot" }, 45 | { "title": "419 Page Expired (Laravel)" }, 46 | { "title": "420 Page Expired (Spring Framework)" }, 47 | { "title": "421 Misdirected Request" }, 48 | { "title": "422 Unprocessable Entity" }, 49 | { "title": "423 Locked" }, 50 | { "title": "424 Failed Dependency" }, 51 | { "title": "425 Too Early" }, 52 | { "title": "426 Upgrade Required" }, 53 | { "title": "428 Precondition Required" }, 54 | { "title": "429 Too Many Requests" }, 55 | { "title": "430 Request Header Fields Too Large (Shopify)" }, 56 | { "title": "431 Request Header Fields Too Large" }, 57 | { "title": "450 Blocked by Windows Parental Controls (Microsoft)" }, 58 | { "title": "451 Unavailable For Legal Reasons" }, 59 | { "title": "500 Internal Server Error" }, 60 | { "title": "501 Not Implemented" }, 61 | { "title": "502 Bad Gateway" }, 62 | { "title": "503 Service Unavailable" }, 63 | { "title": "504 Gateway Timeout" }, 64 | { "title": "505 HTTP Version Not Supported" }, 65 | { "title": "506 Variant Also Negotiates" }, 66 | { "title": "507 Insufficient Storage" }, 67 | { "title": "508 Loop Detected" }, 68 | { "title": "509 Bandwidth Limit Exceeded (Apache Web Server/cPanel)" }, 69 | { "title": "510 Not Extended" }, 70 | { "title": "511 Network Authentication Required" } 71 | ] 72 | } 73 | 74 | -------------------------------------------------------------------------------- /scripts/extra-utilities/named-css-colors.csv: -------------------------------------------------------------------------------- 1 | aliceblue,#F0F8FF 2 | antiquewhite,#FAEBD7 3 | aqua,#00FFFF 4 | aquamarine,#7FFFD4 5 | azure,#F0FFFF 6 | beige,#F5F5DC 7 | bisque,#FFE4C4 8 | black,#000000 9 | blanchedalmond,#FFEBCD 10 | blue,#0000FF 11 | blueviolet,#8A2BE2 12 | brown,#A52A2A 13 | burlywood,#DEB887 14 | cadetblue,#5F9EA0 15 | chartreuse,#7FFF00 16 | chocolate,#D2691E 17 | coral,#FF7F50 18 | cornflowerblue,#6495ED 19 | cornsilk,#FFF8DC 20 | crimson,#DC143C 21 | cyan,#00FFFF 22 | darkblue,#00008B 23 | darkcyan,#008B8B 24 | darkgoldenrod,#B8860B 25 | darkgray,#A9A9A9 26 | darkgreen,#006400 27 | darkgrey,#A9A9A9 28 | darkkhaki,#BDB76B 29 | darkmagenta,#8B008B 30 | darkolivegreen,#556B2F 31 | darkorange,#FF8C00 32 | darkorchid,#9932CC 33 | darkred,#8B0000 34 | darksalmon,#E9967A 35 | darkseagreen,#8FBC8F 36 | darkslateblue,#483D8B 37 | darkslategray,#2F4F4F 38 | darkslategrey,#2F4F4F 39 | darkturquoise,#00CED1 40 | darkviolet,#9400D3 41 | deeppink,#FF1493 42 | deepskyblue,#00BFFF 43 | dimgray,#696969 44 | dimgrey,#696969 45 | dodgerblue,#1E90FF 46 | firebrick,#B22222 47 | floralwhite,#FFFAF0 48 | forestgreen,#228B22 49 | fuchsia,#FF00FF 50 | gainsboro,#DCDCDC 51 | ghostwhite,#F8F8FF 52 | gold,#FFD700 53 | goldenrod,#DAA520 54 | gray,#808080 55 | green,#008000 56 | greenyellow,#ADFF2F 57 | grey,#808080 58 | honeydew,#F0FFF0 59 | hotpink,#FF69B4 60 | indianred,#CD5C5C 61 | indigo,#4B0082 62 | ivory,#FFFFF0 63 | khaki,#F0E68C 64 | lavender,#E6E6FA 65 | lavenderblush,#FFF0F5 66 | lawngreen,#7CFC00 67 | lemonchiffon,#FFFACD 68 | lightblue,#ADD8E6 69 | lightcoral,#F08080 70 | lightcyan,#E0FFFF 71 | lightgoldenrodyellow,#FAFAD2 72 | lightgray,#D3D3D3 73 | lightgreen,#90EE90 74 | lightgrey,#D3D3D3 75 | lightpink,#FFB6C1 76 | lightsalmon,#FFA07A 77 | lightseagreen,#20B2AA 78 | lightskyblue,#87CEFA 79 | lightslategray,#778899 80 | lightslategrey,#778899 81 | lightsteelblue,#B0C4DE 82 | lightyellow,#FFFFE0 83 | lime,#00FF00 84 | limegreen,#32CD32 85 | linen,#FAF0E6 86 | magenta,#FF00FF 87 | maroon,#800000 88 | mediumaquamarine,#66CDAA 89 | mediumblue,#0000CD 90 | mediumorchid,#BA55D3 91 | mediumpurple,#9370DB 92 | mediumseagreen,#3CB371 93 | mediumslateblue,#7B68EE 94 | mediumspringgreen,#00FA9A 95 | mediumturquoise,#48D1CC 96 | mediumvioletred,#C71585 97 | midnightblue,#191970 98 | mintcream,#F5FFFA 99 | mistyrose,#FFE4E1 100 | moccasin,#FFE4B5 101 | navajowhite,#FFDEAD 102 | navy,#000080 103 | oldlace,#FDF5E6 104 | olive,#808000 105 | olivedrab,#6B8E23 106 | orange,#FFA500 107 | orangered,#FF4500 108 | orchid,#DA70D6 109 | palegoldenrod,#EEE8AA 110 | palegreen,#98FB98 111 | paleturquoise,#AFEEEE 112 | palevioletred,#DB7093 113 | papayawhip,#FFEFD5 114 | peachpuff,#FFDAB9 115 | peru,#CD853F 116 | pink,#FFC0CB 117 | plum,#DDA0DD 118 | powderblue,#B0E0E6 119 | purple,#800080 120 | rebeccapurple,#663399 121 | red,#FF0000 122 | rosybrown,#BC8F8F 123 | royalblue,#4169E1 124 | saddlebrown,#8B4513 125 | salmon,#FA8072 126 | sandybrown,#F4A460 127 | seagreen,#2E8B57 128 | seashell,#FFF5EE 129 | sienna,#A0522D 130 | silver,#C0C0C0 131 | skyblue,#87CEEB 132 | slateblue,#6A5ACD 133 | slategray,#708090 134 | slategrey,#708090 135 | snow,#FFFAFA 136 | springgreen,#00FF7F 137 | steelblue,#4682B4 138 | tan,#D2B48C 139 | teal,#008080 140 | thistle,#D8BFD8 141 | tomato,#FF6347 142 | turquoise,#40E0D0 143 | violet,#EE82EE 144 | wheat,#F5DEB3 145 | white,#FFFFFF 146 | whitesmoke,#F5F5F5 147 | yellow,#FFFF00 148 | yellowgreen,#9ACD32 149 | -------------------------------------------------------------------------------- /scripts/extra-utilities/named-css-colors.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env osascript -l JavaScript 2 | ObjC.import("stdlib"); 3 | const app = Application.currentApplication(); 4 | app.includeStandardAdditions = true; 5 | //────────────────────────────────────────────────────────────────────────────── 6 | 7 | /** @param {string} path */ 8 | function readFile(path) { 9 | const data = $.NSFileManager.defaultManager.contentsAtPath(path); 10 | const str = $.NSString.alloc.initWithDataEncoding(data, $.NSUTF8StringEncoding); 11 | return ObjC.unwrap(str); 12 | } 13 | 14 | //────────────────────────────────────────────────────────────────────────────── 15 | 16 | // biome-ignore lint/correctness/noUnusedVariables: Alfred run 17 | function run() { 18 | const jsonPath = 19 | $.getenv("alfred_preferences") + 20 | "/workflows/" + 21 | $.getenv("alfred_workflow_uid") + 22 | "/scripts/extra-utilities/named-css-colors.csv"; 23 | 24 | const colors = readFile(jsonPath) 25 | .split("\n") 26 | .map((/** @type {string} */ line) => { 27 | const [name, hex] = line.split(",") || ["", ""]; 28 | 29 | // so searching for a base color name also matches the color 30 | const baseColor = 31 | name.match(/blue|green|red|yellow|orange|white|gr[ae]y|black|purple/) || ""; 32 | return { 33 | title: name, 34 | subtitle: hex, 35 | arg: name, 36 | match: name + " " + baseColor, 37 | icon: { path: `./scripts/extra-utilities/color-svgs/${name}.svg` }, 38 | }; 39 | }); 40 | 41 | return JSON.stringify({ 42 | items: colors, 43 | cache: { 44 | seconds: 3600 * 24 * 7, // 7 days 45 | loosereload: true, 46 | }, 47 | }); 48 | } 49 | -------------------------------------------------------------------------------- /scripts/extra-utilities/reload-cache.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env osascript -l JavaScript 2 | ObjC.import("stdlib"); 3 | //────────────────────────────────────────────────────────────────────────────── 4 | 5 | // biome-ignore lint/correctness/noUnusedVariables: Alfred run 6 | function run() { 7 | const workflowId = $.getenv("alfred_workflow_bundleid"); 8 | const alfredApp = Application("com.runningwithcrayons.Alfred"); 9 | alfredApp.reloadWorkflow(workflowId); 10 | } 11 | -------------------------------------------------------------------------------- /scripts/extra-utilities/sounds-preview.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env osascript -l JavaScript 2 | ObjC.import("stdlib"); 3 | const app = Application.currentApplication(); 4 | app.includeStandardAdditions = true; 5 | //────────────────────────────────────────────────────────────────────────────── 6 | 7 | /** @param {string} str */ 8 | function camelCaseMatch(str) { 9 | const subwords = str.replace(/[-_./]/g, " "); 10 | const fullword = str.replace(/[-_./]/g, ""); 11 | const camelCaseSeparated = str.replace(/([A-Z])/g, " $1"); 12 | return [subwords, camelCaseSeparated, fullword, str].join(" ") + " "; 13 | } 14 | 15 | //────────────────────────────────────────────────────────────────────────────── 16 | 17 | /** @type {AlfredRun} */ 18 | // biome-ignore lint/correctness/noUnusedVariables: Alfred run 19 | function run() { 20 | const shellCmd = 21 | 'find "/System/Library/Sounds" "/System/Library/Components/CoreAudio.component/Contents/SharedSupport/SystemSounds" -name "*.aif" -or -name "*.aiff" -or -name "*.caf" -not -path "*telephony*"'; 22 | 23 | /** @type AlfredItem[] */ 24 | const soundsArr = app 25 | .doShellScript(shellCmd) 26 | .split("\r") 27 | .map((path) => { 28 | const filename = path.split("/").pop()?.split(".")[0] || "unknown"; 29 | return { 30 | title: filename, 31 | match: camelCaseMatch(filename), 32 | arg: path, 33 | }; 34 | }); 35 | 36 | return JSON.stringify({ 37 | items: soundsArr, 38 | cache: { loosereload: true, seconds: 3600 }, 39 | }); 40 | } 41 | -------------------------------------------------------------------------------- /scripts/manual-docs-searches/CodeMirror.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisgrieser/alfred-docs-searches/f0f9f41fa408c877facad81e27eee3e759520b31/scripts/manual-docs-searches/CodeMirror.png -------------------------------------------------------------------------------- /scripts/manual-docs-searches/biome-docs-search.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env osascript -l JavaScript 2 | ObjC.import("stdlib"); 3 | const app = Application.currentApplication(); 4 | app.includeStandardAdditions = true; 5 | //────────────────────────────────────────────────────────────────────────────── 6 | 7 | /** @param {string} str */ 8 | function alfredMatcher(str) { 9 | const camelCaseSeparated = str.replace(/([A-Z])/g, " $1"); 10 | return [camelCaseSeparated, str].join(" ") + " "; 11 | } 12 | 13 | /** @param {string} url @return {string} */ 14 | function httpRequest(url) { 15 | const queryURL = $.NSURL.URLWithString(url); 16 | const data = $.NSData.dataWithContentsOfURL(queryURL); 17 | return $.NSString.alloc.initWithDataEncoding(data, $.NSUTF8StringEncoding).js; 18 | } 19 | 20 | //────────────────────────────────────────────────────────────────────────────── 21 | 22 | /** @type {AlfredRun} */ 23 | // biome-ignore lint/correctness/noUnusedVariables: Alfred run 24 | function run() { 25 | const docsUrl = "https://api.github.com/repos/biomejs/website/git/trees/main?recursive=1"; 26 | const baseUrl = "https://biomejs.dev"; 27 | 28 | // `\w{3,}` excludes translations of the docs, which are in folders like 29 | // `/ja/` or `/zh-CN/` https://github.com/biomejs/website/tree/main/src/content/docs 30 | const docPathRegex = /^src\/content\/docs\/(\w{3,}.*)\.mdx?$/; 31 | 32 | const response = JSON.parse(httpRequest(docsUrl)); 33 | if (!response) return JSON.stringify({ items: [{ title: "Could not load.", valid: false }] }); 34 | 35 | const workArray = response.tree.map((/** @type {{ path: string; }} */ entry) => { 36 | const path = entry.path; 37 | const [_, subsite] = path.match(docPathRegex) || []; 38 | 39 | if (!subsite) return {}; 40 | if (path.endsWith("404.md")) return {}; 41 | 42 | const parts = subsite.split("/"); 43 | let title = parts.pop() || "??"; 44 | let category = parts.join("/"); 45 | let url = `${baseUrl}/${subsite}`; 46 | 47 | if (subsite.endsWith("index")) { 48 | title = category; 49 | category = ""; 50 | url = `${baseUrl}/${subsite.slice(0, -5)}`; 51 | } 52 | 53 | if (category.endsWith("rules")) { 54 | // camelCase to conform to rule-casing the user expects 55 | title = title.replace(/-\w/g, (match) => match.slice(-1).toUpperCase()); 56 | } else { 57 | // capitalize 58 | title = title.replaceAll("-", " "); 59 | title = title.charAt(0).toUpperCase() + title.slice(1); // capitalize 60 | } 61 | 62 | return { 63 | title: title, 64 | subtitle: category, 65 | match: alfredMatcher(title), 66 | arg: url, 67 | mods: { 68 | cmd: { arg: title }, // copy entry 69 | }, 70 | quicklookurl: url, 71 | uid: title, 72 | }; 73 | }); 74 | 75 | return JSON.stringify({ 76 | items: workArray, 77 | cache: { 78 | seconds: 3600 * 24 * 7, // 7 days 79 | loosereload: true, 80 | }, 81 | }); 82 | } 83 | -------------------------------------------------------------------------------- /scripts/manual-docs-searches/build-obsidian-help-index.mjs: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | // biome-ignore lint/correctness/noNodejsModules: needed here 3 | import fs from "node:fs"; 4 | //────────────────────────────────────────────────────────────────────────────── 5 | 6 | /** @param {string} url */ 7 | async function getGithubJson(url) { 8 | const response = await fetch(url, { 9 | method: "GET", 10 | headers: { 11 | // without `GITHUB_TOKEN`, will hit rate limit when running on Github Actions 12 | // `GITHUB_TOKEN` set via GitHub Actions secrets 13 | // biome-ignore lint/nursery/noProcessEnv: okay here 14 | authorization: "Bearer " + process.env.GITHUB_TOKEN, 15 | "Content-Type": "application/json", 16 | }, 17 | }); 18 | return await response.json(); 19 | } 20 | 21 | /** @param {string} url */ 22 | async function getGithubFileRaw(url) { 23 | const response = await fetch(url); 24 | return await response.text(); 25 | } 26 | 27 | /** INFO not the same Alfred Matcher used in the other scripts 28 | * has to include "#" and "+" as well for headers 29 | * "`" has to be included for inline code in headers 30 | * @param {string} str 31 | */ 32 | function alfredMatcher(str) { 33 | return str.replace(/[-()_#+.`]/g, " ") + " " + str + " "; 34 | } 35 | 36 | //────────────────────────────────────────────────────────────────────────────── 37 | 38 | async function run() { 39 | const docsPages = []; 40 | const officialDocsURL = "https://help.obsidian.md/"; 41 | const rawGitHubUrlRoot = "https://raw.githubusercontent.com/obsidianmd/obsidian-docs/master/"; 42 | const officialDocsTree = 43 | "https://api.github.com/repositories/285425357/git/trees/master?recursive=1"; 44 | 45 | // GUARD 46 | const officialDocsJSON = await getGithubJson(officialDocsTree); 47 | if (!officialDocsJSON) { 48 | console.error("Could not fetch json from: ", officialDocsTree); 49 | process.exit(1); 50 | } 51 | if (!officialDocsJSON.tree) { 52 | console.error("Error: ", JSON.stringify(officialDocsJSON)); 53 | process.exit(1); 54 | } 55 | 56 | // HELP SITES THEMSELVES 57 | const officialDocs = officialDocsJSON.tree 58 | .filter((/** @type {{ path: string; }} */ item) => item.path.match(/en\/.*\.md/)) 59 | .map((/** @type {{ path: string; }} */ item) => item.path); 60 | 61 | for (let path of officialDocs) { 62 | const docUrl = rawGitHubUrlRoot + encodeURI(path); 63 | path = path.replace(/^en\/|\.md$/g, ""); 64 | 65 | const parts = path.split("/"); 66 | const title = parts.pop(); 67 | const area = parts.join("/"); 68 | console.info("Indexing: ", title); 69 | 70 | const rawText = await getGithubFileRaw(docUrl); 71 | const permalink = rawText.match(/^permalink: (.*)/m)?.[1] || path.replaceAll(" ", "+"); 72 | const siteUrl = officialDocsURL + permalink; 73 | 74 | docsPages.push({ 75 | title: title, 76 | match: alfredMatcher(title) + alfredMatcher(area), 77 | subtitle: area, 78 | mods: { 79 | cmd: { arg: title }, // copy entry 80 | }, 81 | uid: siteUrl, 82 | arg: siteUrl, 83 | quicklookurl: siteUrl, 84 | }); 85 | 86 | // HEADINGS 87 | const docTextLines = rawText.split("\n").filter((line) => line.startsWith("#")); 88 | 89 | for (const headingLine of docTextLines) { 90 | const headerName = headingLine.replace(/^#+ /, ""); 91 | const headingUrl = siteUrl + "#" + headerName.replaceAll(" ", "+"); 92 | const displayHeader = headerName.replaceAll("`", ""); // inline code in headings 93 | 94 | docsPages.push({ 95 | title: displayHeader, 96 | subtitle: path, 97 | uid: headingUrl, 98 | match: alfredMatcher(headerName) + alfredMatcher(title) + alfredMatcher(area), 99 | mods: { 100 | cmd: { arg: headerName }, // copy entry 101 | }, 102 | arg: headingUrl, 103 | quicklookurl: headingUrl, 104 | }); 105 | } 106 | } 107 | 108 | const docsJson = { 109 | items: docsPages, 110 | cache: { seconds: 60 * 60 * 24 * 7, loosereload: true }, 111 | }; 112 | 113 | if (!fs.existsSync("./.github/caches/")) fs.mkdirSync("./.github/caches/", { recursive: true }); 114 | const beautifiedForBetterDiff = JSON.stringify(docsJson, null, 2); 115 | fs.writeFileSync("./.github/caches/obsidian-help-index.json", beautifiedForBetterDiff); 116 | } 117 | 118 | await run(); 119 | -------------------------------------------------------------------------------- /scripts/manual-docs-searches/ddg-help.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env osascript -l JavaScript 2 | ObjC.import("stdlib"); 3 | const app = Application.currentApplication(); 4 | app.includeStandardAdditions = true; 5 | //────────────────────────────────────────────────────────────────────────────── 6 | 7 | /** @param {string} url @return {string} */ 8 | function httpRequest(url) { 9 | const queryURL = $.NSURL.URLWithString(url); 10 | const data = $.NSData.dataWithContentsOfURL(queryURL); 11 | return $.NSString.alloc.initWithDataEncoding(data, $.NSUTF8StringEncoding).js; 12 | } 13 | 14 | /** @param {string} str @return {string} */ 15 | function prettyString(str) { 16 | const capitalized = str.charAt(0).toUpperCase() + str.slice(1); 17 | return capitalized.replaceAll("-", " "); 18 | } 19 | 20 | //────────────────────────────────────────────────────────────────────────────── 21 | 22 | /** @type {AlfredRun} */ 23 | // biome-ignore lint/correctness/noUnusedVariables: Alfred run 24 | function run() { 25 | const docsURL = 26 | "https://api.github.com/repos/duckduckgo/duckduckgo-help-pages/git/trees/master?recursive=1"; 27 | const baseURL = "https://duckduckgo.com/duckduckgo-help-pages"; 28 | 29 | const workArray = JSON.parse(httpRequest(docsURL)).tree.map( 30 | (/** @type {{ path: string; }} */ entry) => { 31 | const path = entry.path; 32 | const [_, subsite] = path.match(/^_docs\/(.*)\.md$/) || []; 33 | if (!subsite || subsite.startsWith("_")) return {}; 34 | 35 | const url = `${baseURL}/${subsite}`; 36 | let [category, title] = subsite.split("/"); 37 | if (!title) { 38 | title = category 39 | category = ""; 40 | } 41 | 42 | return { 43 | title: prettyString(title), 44 | subtitle: prettyString(category), 45 | mods: { 46 | cmd: { arg: subsite }, // copy entry 47 | }, 48 | arg: url, 49 | quicklookurl: url, 50 | uid: subsite, 51 | }; 52 | }, 53 | ); 54 | 55 | return JSON.stringify({ 56 | items: workArray, 57 | cache: { 58 | seconds: 3600 * 24 * 7, // 7 days 59 | loosereload: true, 60 | }, 61 | }); 62 | } 63 | -------------------------------------------------------------------------------- /scripts/manual-docs-searches/obsi-developer-docs-search.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env osascript -l JavaScript 2 | ObjC.import("stdlib"); 3 | const app = Application.currentApplication(); 4 | app.includeStandardAdditions = true; 5 | //────────────────────────────────────────────────────────────────────────────── 6 | 7 | /** @param {string} str */ 8 | function camelCaseMatch(str) { 9 | const subwords = str.replace(/[-_./'()]/g, " "); 10 | const fullword = str.replace(/[-_./'()]/g, ""); 11 | const camelCaseSeparated = str.replace(/([A-Z])/g, " $1"); 12 | return [subwords, camelCaseSeparated, fullword, str].join(" ") + " "; 13 | } 14 | 15 | /** @param {string} url @return {string} */ 16 | function httpRequest(url) { 17 | const queryURL = $.NSURL.URLWithString(url); 18 | const data = $.NSData.dataWithContentsOfURL(queryURL); 19 | const requestStr = $.NSString.alloc.initWithDataEncoding(data, $.NSUTF8StringEncoding).js; 20 | return requestStr; 21 | } 22 | 23 | //────────────────────────────────────────────────────────────────────────────── 24 | 25 | /** @type {AlfredRun} */ 26 | // biome-ignore lint/correctness/noUnusedVariables: Alfred run 27 | function run() { 28 | const obsiDocsSource = 29 | "https://api.github.com/repos/obsidianmd/obsidian-developer-docs/git/trees/main?recursive=1"; 30 | const obsiDocsBaseURL = "https://docs.obsidian.md"; 31 | 32 | const obsiDocs = JSON.parse(httpRequest(obsiDocsSource)) 33 | .tree.filter( 34 | (/** @type {{ path: string; }} */ file) => 35 | file.path.startsWith("en/") && file.path.endsWith(".md"), 36 | ) 37 | .map((/** @type {{ path: string }} */ file) => { 38 | const subsitePath = file.path.slice(3, -3); 39 | const subsiteURL = subsitePath.replaceAll(" ", "+"); // obsidian publish uses `+` 40 | const title = subsitePath.replace(/.*\//, ""); // show only file name 41 | const category = subsitePath 42 | .replace(/(.*)\/.*/, "$1") // only parent 43 | .replaceAll("/", " → "); // nicer tree 44 | const url = `${obsiDocsBaseURL}/${subsiteURL}`; 45 | 46 | return { 47 | title: title, 48 | subtitle: category, 49 | match: camelCaseMatch(title), 50 | arg: url, 51 | mods: { 52 | cmd: { arg: title }, // copy entry 53 | }, 54 | quicklookurl: url, 55 | uid: url, 56 | }; 57 | }); 58 | 59 | //─────────────────────────────────────────────────────────────────────────── 60 | 61 | const codeMirrorDocsSource = "https://codemirror.net/docs/ref/"; 62 | const ahrefRegex = / line.includes('a href="#')) 67 | .map((line) => { 68 | const [_, anchor] = line.match(ahrefRegex) || [null, null]; 69 | if (!anchor) return {}; 70 | const url = codeMirrorDocsSource + anchor; 71 | const data = decodeURIComponent(anchor).slice(1); 72 | 73 | const [__, category, title] = data.match(/(.*)[.^](.*)/) || [null, "@codemirror", data]; 74 | 75 | return { 76 | title: title, 77 | subtitle: category, 78 | match: camelCaseMatch(title), 79 | icon: { path: "./scripts/manual-docs-searches/CodeMirror.png" }, 80 | mods: { 81 | cmd: { arg: title }, // copy entry 82 | }, 83 | arg: url, 84 | quicklookurl: url, 85 | uid: url, 86 | }; 87 | }); 88 | 89 | return JSON.stringify({ 90 | items: [...obsiDocs, ...codeMirrorDocs], 91 | cache: { 92 | seconds: 3600 * 24 * 7, // 7 days 93 | loosereload: true, 94 | }, 95 | }); 96 | } 97 | -------------------------------------------------------------------------------- /scripts/manual-docs-searches/pandoc-docs.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env osascript -l JavaScript 2 | ObjC.import("stdlib"); 3 | const app = Application.currentApplication(); 4 | app.includeStandardAdditions = true; 5 | //────────────────────────────────────────────────────────────────────────────── 6 | 7 | /** @param {string} str */ 8 | function alfredMatcher(str) { 9 | const clean = str.replace(/[<_-]/g, " "); 10 | return [clean, str].join(" ") + " "; 11 | } 12 | 13 | //────────────────────────────────────────────────────────────────────────────── 14 | /** @type {AlfredRun} */ 15 | // biome-ignore lint/correctness/noUnusedVariables: Alfred run 16 | function run() { 17 | /** @type {string[]} */ 18 | let breadcrumbs = []; 19 | const pandocDocsUrl = "https://pandoc.org/MANUAL.html"; 20 | 21 | const sectionsArr = app 22 | .doShellScript(`curl -s "${pandocDocsUrl}"`) 23 | .split(">") // INFO split by tags, not lines, since html formatting breaks up some tags across lines 24 | .filter( 25 | (htmlTag) => 26 | (htmlTag.includes(" { 30 | htmlTag = htmlTag.replaceAll("\r", ""); 31 | const [_, name, levelStr] = htmlTag.match(/id="(.*?)"\s*class="(.*?)"/) || []; 32 | if (!name || !levelStr) return {}; 33 | const url = `${pandocDocsUrl}#${name}`; 34 | 35 | let displayName = name 36 | .replace(/-\d$/, "") 37 | .replace(/^extension-/, "") 38 | .replace(/^option--/, "--") 39 | .replace(/\[$/, ""); // FIX brackets leftover in pandoc html 40 | 41 | // construct breadcrumbs based on order of appearenace of headings 42 | const lvl = levelStr.match(/\d/) ? Number.parseInt(levelStr.match(/\d/)?.[0] || "0") : null; 43 | if (lvl) { 44 | // options do not get a section level 45 | breadcrumbs[lvl - 1] = displayName; // set current level 46 | breadcrumbs = breadcrumbs.slice(0, lvl); // delete headings of lower level 47 | } 48 | const parentsBreadcrumbs = breadcrumbs 49 | .slice(0, -1) // remove last element, since it's the name 50 | .join(" > ") // separator 51 | .replaceAll("-", " ") 52 | .replace(/ > $/, ""); // trailing separator appears when heading levels are skipped in the html 53 | 54 | if (parentsBreadcrumbs !== "extensions" && parentsBreadcrumbs !== "options") { 55 | displayName = displayName.replaceAll("-", " "); 56 | displayName = displayName.charAt(0).toUpperCase() + displayName.slice(1); // capitalize 57 | } 58 | 59 | return { 60 | title: displayName, 61 | subtitle: parentsBreadcrumbs, 62 | match: alfredMatcher(displayName) + alfredMatcher(parentsBreadcrumbs), 63 | arg: url, 64 | mods: { 65 | cmd: { arg: name }, // copy entry 66 | }, 67 | quicklookurl: url, 68 | uid: url, 69 | }; 70 | }); 71 | 72 | return JSON.stringify({ 73 | items: sectionsArr, 74 | cache: { 75 | seconds: 3600 * 24 * 7, // 7 days 76 | loosereload: true, 77 | }, 78 | }); 79 | } 80 | -------------------------------------------------------------------------------- /scripts/manual-docs-searches/ruff-rules.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env osascript -l JavaScript 2 | ObjC.import("stdlib"); 3 | const app = Application.currentApplication(); 4 | app.includeStandardAdditions = true; 5 | 6 | /** @param {string} str */ 7 | function alfredMatcher(str) { 8 | const clean = str.replace(/[<_-]/g, " "); 9 | const numberSeparated = str.replace(/(\d+)/g, " $1"); 10 | return [clean, str, numberSeparated].join(" ") + " "; 11 | } 12 | 13 | //────────────────────────────────────────────────────────────────────────────── 14 | /** @type {AlfredRun} */ 15 | // biome-ignore lint/correctness/noUnusedVariables: Alfred run 16 | function run() { 17 | const ruffRulesUrl = "https://docs.astral.sh/ruff/rules/"; 18 | 19 | const sectionsArr = app 20 | .doShellScript(`curl -s "${ruffRulesUrl}" | grep -A1 " { 23 | const [idRaw, nameRaw] = ruleInfo.split("\r"); 24 | const [_, id] = idRaw.match(/id="(.*?)"/) || []; 25 | const [__, name] = nameRaw.includes("href") 26 | ? nameRaw.match(/href="(.*?)\/"/) || [] 27 | : nameRaw.match(/>(.*?)<.*/) || []; 28 | const displayName = name.replace(/-/g, " "); 29 | const url = ruffRulesUrl + name + "/"; 30 | 31 | /** @type{AlfredItem} */ 32 | const item = { 33 | title: displayName, 34 | subtitle: id, 35 | match: alfredMatcher(id) + alfredMatcher(name), 36 | arg: url, 37 | quicklookurl: url, 38 | mods: { 39 | cmd: { arg: name }, // copy entry 40 | }, 41 | uid: url, 42 | }; 43 | return item; 44 | }); 45 | 46 | return JSON.stringify({ 47 | items: sectionsArr, 48 | cache: { 49 | seconds: 3600 * 24 * 7, // 7 days 50 | loosereload: true, 51 | }, 52 | }); 53 | } 54 | -------------------------------------------------------------------------------- /scripts/manual-docs-searches/shellcheck-wiki.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env osascript -l JavaScript 2 | ObjC.import("stdlib"); 3 | const app = Application.currentApplication(); 4 | app.includeStandardAdditions = true; 5 | 6 | //────────────────────────────────────────────────────────────────────────────── 7 | 8 | /** @type {AlfredRun} */ 9 | // biome-ignore lint/correctness/noUnusedVariables: Alfred run 10 | function run() { 11 | const baseURL = "https://www.shellcheck.net/wiki/"; 12 | const ahrefRegex = /.*?href='(.*?)'>.*?<\/a>(.*?)(<\/li>|$)/i; 13 | 14 | const jsonArr = app 15 | .doShellScript(`curl -sL '${baseURL}'`) 16 | .split("\r") 17 | .slice(3, -1) 18 | .map((/** @type {string} */ line) => { 19 | const title = line.replace(ahrefRegex, "$1"); 20 | if (title === "") return {}; 21 | const desc = line.replace(ahrefRegex, "$2").replaceAll("–", "").trim(); 22 | const url = baseURL + title; 23 | 24 | // if rule with number, add the number alone to the matcher as well 25 | const hasNumber = title.match(/\d{4}$/); 26 | const numberMatcher = hasNumber ? " " + hasNumber[0] : ""; 27 | 28 | return { 29 | title: title, 30 | subtitle: desc, 31 | match: title + numberMatcher, 32 | mods: { 33 | cmd: { arg: title }, // copy entry 34 | }, 35 | arg: url, 36 | quicklookurl: url, 37 | uid: url, 38 | }; 39 | }); 40 | 41 | return JSON.stringify({ 42 | items: jsonArr, 43 | cache: { 44 | seconds: 3600 * 24 * 7, // 7 days 45 | loosereload: true, 46 | }, 47 | }); 48 | } 49 | -------------------------------------------------------------------------------- /scripts/manual-docs-searches/wezterm-docs-search.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env osascript -l JavaScript 2 | ObjC.import("stdlib"); 3 | const app = Application.currentApplication(); 4 | app.includeStandardAdditions = true; 5 | //────────────────────────────────────────────────────────────────────────────── 6 | 7 | /** @param {string} str */ 8 | function alfredMatcher(str) { 9 | const clean = str.replace(/[-_]/g, " "); 10 | return [clean, str].join(" "); 11 | } 12 | 13 | //────────────────────────────────────────────────────────────────────────────── 14 | /** @type {AlfredRun} */ 15 | // biome-ignore lint/correctness/noUnusedVariables: Alfred run 16 | function run() { 17 | const docsURL = "https://api.github.com/repos/wez/wezterm/git/trees/main?recursive=1"; 18 | const baseURL = "https://wezterm.org"; 19 | const docPathRegex = /^docs\/.*\.md$/i; 20 | 21 | const workArray = JSON.parse(app.doShellScript(`curl -sL "${docsURL}"`)) 22 | .tree.filter((/** @type {{ path: string; }} */ file) => docPathRegex.test(file.path)) 23 | .reverse() 24 | .map((/** @type {{ path: string }} */ entry) => { 25 | const entryPath = entry.path.slice(5, -3); 26 | const parts = entryPath.split("/"); 27 | const title = parts.pop() || "??"; 28 | const category = parts.join("/"); 29 | const url = `${baseURL}/${entryPath}`; 30 | 31 | return { 32 | title: title, 33 | subtitle: category, 34 | match: alfredMatcher(entryPath), 35 | mods: { 36 | cmd: { arg: entryPath }, // copy entry 37 | }, 38 | arg: url, 39 | quicklookurl: url, 40 | uid: entryPath, 41 | }; 42 | }); 43 | 44 | return JSON.stringify({ 45 | items: workArray, 46 | cache: { 47 | seconds: 3600 * 24 * 7, // 7 days 48 | loosereload: true, 49 | }, 50 | }); 51 | } 52 | -------------------------------------------------------------------------------- /scripts/manual-docs-searches/yq-docs.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env osascript -l JavaScript 2 | ObjC.import("stdlib"); 3 | const app = Application.currentApplication(); 4 | app.includeStandardAdditions = true; 5 | //────────────────────────────────────────────────────────────────────────────── 6 | 7 | /** @param {string} url @return {string} */ 8 | function httpRequest(url) { 9 | const queryURL = $.NSURL.URLWithString(url); 10 | const data = $.NSData.dataWithContentsOfURL(queryURL); 11 | return $.NSString.alloc.initWithDataEncoding(data, $.NSUTF8StringEncoding).js; 12 | } 13 | //────────────────────────────────────────────────────────────────────────────── 14 | 15 | /** @type {AlfredRun} */ 16 | // biome-ignore lint/correctness/noUnusedVariables: Alfred run 17 | function run() { 18 | const docsURL = "https://api.github.com/repos/mikefarah/yq/git/trees/master?recursive=1"; 19 | const baseURL = "https://mikefarah.gitbook.io/yq"; 20 | const docPathRegex = /^pkg\/yqlib\/doc\/(.*)\.md$/i; 21 | 22 | const workArray = JSON.parse(httpRequest(docsURL)).tree.map( 23 | (/** @type {{ path: string; }} */ entry) => { 24 | const path = entry.path; 25 | if ( 26 | !docPathRegex.test(path) || 27 | path.includes("/headers/") || 28 | path.endsWith("notification-snippet.md") 29 | ) { 30 | return {}; 31 | } 32 | 33 | const subsite = path.replace(docPathRegex, "$1"); 34 | const [category, title] = subsite.split("/"); 35 | const url = `${baseURL}/${subsite}`; 36 | 37 | return { 38 | title: title.replaceAll("-", " "), 39 | subtitle: category, 40 | mods: { 41 | cmd: { arg: title }, // copy entry 42 | }, 43 | arg: url, 44 | quicklookurl: url, 45 | uid: subsite, 46 | }; 47 | }, 48 | ); 49 | 50 | return JSON.stringify({ 51 | items: workArray, 52 | cache: { 53 | seconds: 3600 * 24 * 7, // 7 days 54 | loosereload: true, 55 | }, 56 | }); 57 | } 58 | --------------------------------------------------------------------------------