├── .gitignore ├── .python-version ├── .travis.yml ├── README.md ├── install.py ├── poetry.lock ├── pyproject.toml └── src ├── alfred-2 └── info.plist ├── alfred-3 └── info.plist └── main ├── 68637FD7-2E45-4403-B3E4-DD061FD0FF47.png ├── alfredhelp.py ├── icon.png └── info.plist /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .idea/ 3 | *.ipr 4 | *.iws 5 | *.pyc 6 | .idea_modules/ 7 | *_cache/ 8 | .vscode/ 9 | /build/ -------------------------------------------------------------------------------- /.python-version: -------------------------------------------------------------------------------- 1 | 2.7.17 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - '2.7' 4 | before_install: 5 | - if echo "$TRAVIS_COMMIT_MESSAGE" | grep -F -q "[skip ci]" ; then echo "[skip ci] 6 | found, exiting" && exit 0 ; fi 7 | - pip install poetry 8 | install: 9 | - poetry install 10 | script: 11 | - poetry version minor 12 | - poetry run python install.py --build 13 | - git config --global user.email "builds@travis-ci.org" 14 | - git config --global user.name "Travis CI" 15 | - RELEASE_VERSION=`poetry version | awk '{print $2}'` 16 | - git add pyproject.toml 17 | - git commit -m "Release version ${RELEASE_VERSION}" -m "Travis build $TRAVIS_BUILD_NUMBER 18 | [skip ci]" 19 | - poetry version preminor 20 | - git add pyproject.toml 21 | - VERSION=`poetry version | awk '{print $2}'` 22 | - git commit -m "Start version ${VERSION}" -m "Travis build $TRAVIS_BUILD_NUMBER [skip 23 | ci]" 24 | before_deploy: 25 | - git tag -f "v${RELEASE_VERSION}" 26 | deploy: 27 | provider: releases 28 | api_key: 29 | secure: Xlu114ePToyscFkmN44m1I2lgfj8Nr8sMnY3oyQ+LfMTG9gN4tQqK8/DWUokrUbhbV2ywZTy5vFwXWmBWpn9kKTRvo0x8ytmxFz6pFZIdTkJT9GFm5p7vXjRqkkj474gilkprEty090FICPNvT4TwA+EoOY6W8WM2Z+woyzxtB7M9bXKS1LJ3T1vAcIQXt/1p85dKeTkusI21LOCUncu+ZMYK6rTAPDewcE5sw+iCji7h67pQ9EoHbVVZEecEuYgUfm6XYm3ykVA9O3RK1t+rX/LR8C+tuN+zdBC07oEURvof/hVffdNy24VtyPyuTND5wpho7/5qvqvcB8FYiZXMMBBMELL7XXuhv5F+Kk1KbSdgmtaZLq51RiYDczTwjxKc2ggP3/mUwDu6OBVkDhZgjywTQnLb1IOMLmfpj22LzD+yXmXcGwhcwotQ2Nww+0Pl7Ka6alZKZu2AI0C7nyDhOOD993LqwTEiSGYiQFYvVUQKBBafRz11p1jwu/fSMhkHLh34MS93nUb7XbdLppQf8MFEhKCwTModB4aG0kkXsYplGEJJQx3dYjXLdMDxcJGU1u5aMZssTiBParHYE59vt/uTRtJ3MSbislDsZHthFLjwVPVHQikAvRxsMn9Rbja0GN+I7GyGXZ0oFONXvGDtquJsrH1NT9wXVPu0rbmiqE= 30 | file_glob: true 31 | file: build/dist/* 32 | skip_cleanup: true 33 | on: 34 | repo: pochemuto/alfred-help-workflow 35 | branch: master 36 | after_deploy: 37 | - git push "https://pochemuto:${GITHUB_PERSONAL_TOKEN}@github.com/pochemuto/alfred-help-workflow.git" 38 | HEAD:master 39 | env: 40 | global: 41 | - secure: JRX8M3toNaOpJYVDWvNfZkSsEPOjxFTDzsgfmfn9RooxbywfOiejAHSvnbtoSrz5xVyNSF7hRYkPpVEPdPz51M3vi8tRMjr30jOhABSfp8QBB89l9xDdrJFt82QXJPv6Lh8cLpui6pu2CZdiWwJLqfLzkwhnTymiV7WcB4Fsx8EBzhKfLo46MNziFwHwBx3lgD+2FvTTLnWuhoqjtWvqL+K9ubBJIlQP5ws1m2V/uchrrT1sMQfnlXZqVupx1vTWD3/7IxECgIvxaCFBYszklOVgQ3rlErz6bmyl2mSMLro/3blv5RoeYGvgkrA5y6s+tGFGelHIRI1Of+0NXXcT+oc3ikHylL62GwFFQaoW+XpHx+p/i1/i+IwICO/eD4Nf52PjSvejJH00F3hC7lnQKafa9vstp3SN9EBAJk7aPd87ip47KSgEpga++DQDPb2ZzDCT3PpZ2b2O0/SraKMIEAZOSOFQ1d2uGbt9/EPOaAxGTGOHthxh91tTT6OCbpuWRi4JGJcg+ttmPNrNmTLBp5PRe/GDiRbldQetEGf++wz8QzgZD331dc0cr4Z9z4KFw080GVvhiQQw4NqrznrlWWDBahXwNy1BG33UcNFIbjFLJKzja+zgUswFlUW/hUpvO29UtiGOwkNYcxxs6x8TZPEt02FwezldurzB/aqJlSY= 42 | - secure: H6F6cyVq0qNBtF2vtRC+ZR2QmChbxhziBGEVC7BeQfecmVMRvG/faVXZpJKOQ1hIkRGcXGsOpZIhAQvcXTXbxS3yXLilcIkjQfWH5OZzhIM+3mh4gNtOxfn26Yja2ULv0NtNE/bQMRyxf/WK2s8Ot5AxUDt017FkG0GcyY0738pU28PTjvgXZ5fY0V1qC5qpeo7DsswIOZCbd8FXEUvpKabifaNg+2Mo8UESHWGexib2/E7OS/uC581g7DG2N3G4sdCZGuClDRVFkJk6dc5F1jT3S0zUZdn2etZMpEKm/cwsK7w0vowYOD0+xrVe34LjdoFcZMv6WEj5zJmCyJaC3gACtsfG8WjX2K1kRVB4TzZ9PshrwPCXgvh81mi2KVwmiYNmd6YsvIj2rUEHbpKNV3HuPLqmJWNkezbDjzvYmQ9SM7TDjfNGkqo1fH8gegm3WAuKGt9fZmyQ1+YtUDmRfYRcJj+Gmlr2PR2nq/sciHuG3xKwgv35CEOcjMaWzBgJu4gO+g8rI9zCXxN93nVJzKVWyCWfElyLumzQR9/D34RUz7jtHMO7EEYfxFmZdfSqOhwaF90dMZypqz1/X4wJZtMmcqcLOlJA0X9hcw+iZgoz4CzIzr8xDhQjMFkeyMc6XlQtP0mE6jhMbDrU7MA01sS8NlNKMM64EK9E9a4Qsz0= 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Alfred Keywords 2 | -------------------- 3 | 4 | [Latest Release](https://github.com/pochemuto/alfred-help-workflow/releases/latest) 5 | 6 | [![Build Status](https://travis-ci.org/pochemuto/alfred-help-workflow.svg?branch=master)](https://travis-ci.org/pochemuto/alfred-help-workflow) 7 | 8 | Usually, advanced by Alfred have many workflows. Some of them need to use very often, but when you need it is not easy to remember keyword. Alfred had to open the settings or google. At this point, breaks down magic Alfred. 9 | 10 | This workflow helps you remember the keyword. Just enter `?` And the name of the action and you will see a list of available actions. 11 | 12 | Find action with url: 13 | 14 | ![find action with url](https://pochemuto.github.io/alfred-help-workflow/images/ss-url.png) 15 | 16 | How to convert date: 17 | 18 | ![action to convert date](https://pochemuto.github.io/alfred-help-workflow/images/ss-convert-date.png) 19 | 20 | ## Development 21 | - install [poetry](https://python-poetry.org/) 22 | - run `poetry run python install.py --build`. It will produce folders with workflows in `build` folder and packaged versions in `build/dist` -------------------------------------------------------------------------------- /install.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | import argparse 3 | import shutil 4 | import glob 5 | import plistlib 6 | import zipfile 7 | import os 8 | from os import path 9 | import errno 10 | import toml 11 | 12 | import workflow 13 | 14 | SNAPSHOT_SUFFIX = '-SNAPSHOT' 15 | 16 | INFO_PLIST_FILENAME = 'info.plist' 17 | BUILD_TARGET = 'build' 18 | 19 | OUTPUT_FILENAME_PATTERN = 'Alfred.Keywords.Help.v.{version}.{ext}' 20 | 21 | parser = argparse.ArgumentParser() 22 | parser.add_argument('--build', action='store_true') 23 | 24 | TARGET_ALFRED_VERSIONS = [ 25 | {'dir': 'alfred-2', 'ext': 'alfredworkflow'}, 26 | {'dir': 'alfred-3', 'ext': 'alfred3workflow'}, 27 | {'dir': 'alfred-4', 'ext': 'alfred4workflow'} 28 | ] 29 | 30 | 31 | def read_version(): 32 | with open('pyproject.toml') as pyproject: 33 | model = toml.load(pyproject) 34 | return model['tool']['poetry']['version'] 35 | 36 | 37 | def write_workflow_version(target, version): 38 | # workflows framework needs its own version file 39 | with open(path.join(target, 'version'), 'w') as version_file: 40 | version_file.write(version) 41 | 42 | plist_file = path.join(target, INFO_PLIST_FILENAME) 43 | info = plistlib.readPlist(plist_file) 44 | info['version'] = version 45 | plistlib.writePlist(info, plist_file) 46 | 47 | 48 | def copy_deps(target): 49 | pkg = workflow.__path__[0] 50 | shutil.copytree(pkg, path.join(target, path.basename(pkg))) 51 | 52 | 53 | def copy_tree(source, target): 54 | if path.isdir(source): 55 | for filename in os.listdir(source): 56 | copy_tree(path.join(source, filename), path.join(target, filename)) 57 | else: 58 | shutil.copy2(source, target) 59 | 60 | 61 | def build(): 62 | version = read_version() 63 | for alfred_version in TARGET_ALFRED_VERSIONS: 64 | target_path = path.join(BUILD_TARGET, alfred_version['dir']) 65 | shutil.rmtree(target_path, ignore_errors=True) 66 | shutil.copytree('src/main', target_path) 67 | 68 | copy_deps(target_path) 69 | overrides = path.join('src', alfred_version['dir']) 70 | if path.isdir(overrides): 71 | copy_tree(overrides, target_path) 72 | 73 | write_workflow_version(target_path, version) 74 | pack(target_path, version, alfred_version['ext']) 75 | 76 | 77 | def zipdir(root, ziph, strip_root=False): 78 | # ziph is zipfile handle 79 | for current_dir, dirs, files in os.walk(root): 80 | for file in files: 81 | path = os.path.join(current_dir, file) 82 | zip_path = path 83 | if strip_root: 84 | zip_path = os.path.relpath(path, root) 85 | print("adding " + path) 86 | ziph.write(path, arcname=zip_path) 87 | 88 | 89 | def create_zip(source, target): 90 | zipf = zipfile.ZipFile(target, 'w', zipfile.ZIP_DEFLATED) 91 | zipdir(source, zipf, strip_root=True) 92 | zipf.close() 93 | 94 | 95 | def pack(source, version, ext): 96 | dist = path.join(BUILD_TARGET, 'dist') 97 | try: 98 | os.makedirs(dist) 99 | except OSError as e: 100 | if e.errno != errno.EEXIST: 101 | raise 102 | create_zip(source, os.path.join( 103 | dist, OUTPUT_FILENAME_PATTERN.format(version=version, ext=ext))) 104 | 105 | 106 | def main(): 107 | args = parser.parse_args() 108 | 109 | if args.build: 110 | build() 111 | 112 | 113 | if __name__ == '__main__': 114 | main() 115 | -------------------------------------------------------------------------------- /poetry.lock: -------------------------------------------------------------------------------- 1 | [[package]] 2 | category = "main" 3 | description = "Full-featured helper library for writing Alfred 2/3/4 workflows" 4 | name = "alfred-workflow" 5 | optional = false 6 | python-versions = "*" 7 | version = "1.37.2" 8 | 9 | [[package]] 10 | category = "dev" 11 | description = "Atomic file writes." 12 | name = "atomicwrites" 13 | optional = false 14 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 15 | version = "1.3.0" 16 | 17 | [[package]] 18 | category = "dev" 19 | description = "Classes Without Boilerplate" 20 | name = "attrs" 21 | optional = false 22 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 23 | version = "19.3.0" 24 | 25 | [package.extras] 26 | azure-pipelines = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "pytest-azurepipelines"] 27 | dev = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "sphinx", "pre-commit"] 28 | docs = ["sphinx", "zope.interface"] 29 | tests = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"] 30 | 31 | [[package]] 32 | category = "dev" 33 | description = "A tool that automatically formats Python code to conform to the PEP 8 style guide" 34 | name = "autopep8" 35 | optional = false 36 | python-versions = "*" 37 | version = "1.4.4" 38 | 39 | [package.dependencies] 40 | pycodestyle = ">=2.4.0" 41 | 42 | [[package]] 43 | category = "dev" 44 | description = "Cross-platform colored terminal text." 45 | marker = "sys_platform == \"win32\"" 46 | name = "colorama" 47 | optional = false 48 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 49 | version = "0.4.3" 50 | 51 | [[package]] 52 | category = "dev" 53 | description = "Updated configparser from Python 3.7 for Python 2.6+." 54 | marker = "python_version < \"3\"" 55 | name = "configparser" 56 | optional = false 57 | python-versions = ">=2.6" 58 | version = "4.0.2" 59 | 60 | [package.extras] 61 | docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] 62 | testing = ["pytest (>=3.5,<3.7.3 || >3.7.3)", "pytest-checkdocs (>=1.2)", "pytest-flake8", "pytest-black-multipy"] 63 | 64 | [[package]] 65 | category = "dev" 66 | description = "Backports and enhancements for the contextlib module" 67 | marker = "python_version < \"3\"" 68 | name = "contextlib2" 69 | optional = false 70 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 71 | version = "0.6.0.post1" 72 | 73 | [[package]] 74 | category = "dev" 75 | description = "Python function signatures from PEP362 for Python 2.6, 2.7 and 3.2+" 76 | marker = "python_version < \"3.0\"" 77 | name = "funcsigs" 78 | optional = false 79 | python-versions = "*" 80 | version = "1.0.2" 81 | 82 | [[package]] 83 | category = "dev" 84 | description = "Read metadata from Python packages" 85 | name = "importlib-metadata" 86 | optional = false 87 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" 88 | version = "1.3.0" 89 | 90 | [package.dependencies] 91 | zipp = ">=0.5" 92 | 93 | [package.dependencies.configparser] 94 | python = "<3" 95 | version = ">=3.5" 96 | 97 | [package.dependencies.contextlib2] 98 | python = "<3" 99 | version = "*" 100 | 101 | [package.dependencies.pathlib2] 102 | python = "<3" 103 | version = "*" 104 | 105 | [package.extras] 106 | docs = ["sphinx", "rst.linker"] 107 | testing = ["packaging", "importlib-resources"] 108 | 109 | [[package]] 110 | category = "dev" 111 | description = "More routines for operating on iterables, beyond itertools" 112 | name = "more-itertools" 113 | optional = false 114 | python-versions = "*" 115 | version = "5.0.0" 116 | 117 | [package.dependencies] 118 | six = ">=1.0.0,<2.0.0" 119 | 120 | [[package]] 121 | category = "dev" 122 | description = "Core utilities for Python packages" 123 | name = "packaging" 124 | optional = false 125 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 126 | version = "19.2" 127 | 128 | [package.dependencies] 129 | pyparsing = ">=2.0.2" 130 | six = "*" 131 | 132 | [[package]] 133 | category = "dev" 134 | description = "Object-oriented filesystem paths" 135 | marker = "python_version < \"3.6\"" 136 | name = "pathlib2" 137 | optional = false 138 | python-versions = "*" 139 | version = "2.3.5" 140 | 141 | [package.dependencies] 142 | six = "*" 143 | 144 | [package.dependencies.scandir] 145 | python = "<3.5" 146 | version = "*" 147 | 148 | [[package]] 149 | category = "dev" 150 | description = "plugin and hook calling mechanisms for python" 151 | name = "pluggy" 152 | optional = false 153 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 154 | version = "0.13.1" 155 | 156 | [package.dependencies] 157 | [package.dependencies.importlib-metadata] 158 | python = "<3.8" 159 | version = ">=0.12" 160 | 161 | [package.extras] 162 | dev = ["pre-commit", "tox"] 163 | 164 | [[package]] 165 | category = "dev" 166 | description = "library with cross-python path, ini-parsing, io, code, log facilities" 167 | name = "py" 168 | optional = false 169 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 170 | version = "1.8.0" 171 | 172 | [[package]] 173 | category = "dev" 174 | description = "Python style guide checker" 175 | name = "pycodestyle" 176 | optional = false 177 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 178 | version = "2.5.0" 179 | 180 | [[package]] 181 | category = "dev" 182 | description = "Python parsing module" 183 | name = "pyparsing" 184 | optional = false 185 | python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" 186 | version = "2.4.5" 187 | 188 | [[package]] 189 | category = "dev" 190 | description = "pytest: simple powerful testing with Python" 191 | name = "pytest" 192 | optional = false 193 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 194 | version = "4.6.0" 195 | 196 | [package.dependencies] 197 | atomicwrites = ">=1.0" 198 | attrs = ">=17.4.0" 199 | colorama = "*" 200 | importlib-metadata = ">=0.12" 201 | packaging = "*" 202 | pluggy = ">=0.12,<1.0" 203 | py = ">=1.5.0" 204 | six = ">=1.10.0" 205 | wcwidth = "*" 206 | 207 | [[package.dependencies.more-itertools]] 208 | python = "<2.8" 209 | version = ">=4.0.0,<6.0.0" 210 | 211 | [[package.dependencies.more-itertools]] 212 | python = ">=2.8" 213 | version = ">=4.0.0" 214 | 215 | [package.dependencies.funcsigs] 216 | python = "<3.0" 217 | version = ">=1.0" 218 | 219 | [package.dependencies.pathlib2] 220 | python = "<3.6" 221 | version = ">=2.2.0" 222 | 223 | [package.extras] 224 | testing = ["argcomplete", "hypothesis (>=3.56)", "nose", "requests", "mock"] 225 | 226 | [[package]] 227 | category = "dev" 228 | description = "a python refactoring library..." 229 | name = "rope" 230 | optional = false 231 | python-versions = "*" 232 | version = "0.14.0" 233 | 234 | [[package]] 235 | category = "dev" 236 | description = "scandir, a better directory iterator and faster os.walk()" 237 | marker = "python_version < \"3.5\"" 238 | name = "scandir" 239 | optional = false 240 | python-versions = "*" 241 | version = "1.10.0" 242 | 243 | [[package]] 244 | category = "dev" 245 | description = "Python 2 and 3 compatibility utilities" 246 | name = "six" 247 | optional = false 248 | python-versions = ">=2.6, !=3.0.*, !=3.1.*" 249 | version = "1.13.0" 250 | 251 | [[package]] 252 | category = "dev" 253 | description = "Python Library for Tom's Obvious, Minimal Language" 254 | name = "toml" 255 | optional = false 256 | python-versions = "*" 257 | version = "0.10.0" 258 | 259 | [[package]] 260 | category = "dev" 261 | description = "Measures number of Terminal column cells of wide-character codes" 262 | name = "wcwidth" 263 | optional = false 264 | python-versions = "*" 265 | version = "0.1.7" 266 | 267 | [[package]] 268 | category = "dev" 269 | description = "Backport of pathlib-compatible object wrapper for zip files" 270 | name = "zipp" 271 | optional = false 272 | python-versions = ">=2.7" 273 | version = "0.6.0" 274 | 275 | [package.dependencies] 276 | more-itertools = "*" 277 | 278 | [package.extras] 279 | docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] 280 | testing = ["pathlib2", "contextlib2", "unittest2"] 281 | 282 | [metadata] 283 | content-hash = "3612e66a652eec2dfba2a3f91ac11b91adc0765ed58014cf36577131d978a326" 284 | python-versions = "^2.7" 285 | 286 | [metadata.files] 287 | alfred-workflow = [ 288 | {file = "Alfred-Workflow-1.37.2.tar.gz", hash = "sha256:58fd46406bd16fb983e249a3faef444519e8eefdc840f29f037afab468941ded"}, 289 | ] 290 | atomicwrites = [ 291 | {file = "atomicwrites-1.3.0-py2.py3-none-any.whl", hash = "sha256:03472c30eb2c5d1ba9227e4c2ca66ab8287fbfbbda3888aa93dc2e28fc6811b4"}, 292 | {file = "atomicwrites-1.3.0.tar.gz", hash = "sha256:75a9445bac02d8d058d5e1fe689654ba5a6556a1dfd8ce6ec55a0ed79866cfa6"}, 293 | ] 294 | attrs = [ 295 | {file = "attrs-19.3.0-py2.py3-none-any.whl", hash = "sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c"}, 296 | {file = "attrs-19.3.0.tar.gz", hash = "sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72"}, 297 | ] 298 | autopep8 = [ 299 | {file = "autopep8-1.4.4.tar.gz", hash = "sha256:4d8eec30cc81bc5617dbf1218201d770dc35629363547f17577c61683ccfb3ee"}, 300 | ] 301 | colorama = [ 302 | {file = "colorama-0.4.3-py2.py3-none-any.whl", hash = "sha256:7d73d2a99753107a36ac6b455ee49046802e59d9d076ef8e47b61499fa29afff"}, 303 | {file = "colorama-0.4.3.tar.gz", hash = "sha256:e96da0d330793e2cb9485e9ddfd918d456036c7149416295932478192f4436a1"}, 304 | ] 305 | configparser = [ 306 | {file = "configparser-4.0.2-py2.py3-none-any.whl", hash = "sha256:254c1d9c79f60c45dfde850850883d5aaa7f19a23f13561243a050d5a7c3fe4c"}, 307 | {file = "configparser-4.0.2.tar.gz", hash = "sha256:c7d282687a5308319bf3d2e7706e575c635b0a470342641c93bea0ea3b5331df"}, 308 | ] 309 | contextlib2 = [ 310 | {file = "contextlib2-0.6.0.post1-py2.py3-none-any.whl", hash = "sha256:3355078a159fbb44ee60ea80abd0d87b80b78c248643b49aa6d94673b413609b"}, 311 | {file = "contextlib2-0.6.0.post1.tar.gz", hash = "sha256:01f490098c18b19d2bd5bb5dc445b2054d2fa97f09a4280ba2c5f3c394c8162e"}, 312 | ] 313 | funcsigs = [ 314 | {file = "funcsigs-1.0.2-py2.py3-none-any.whl", hash = "sha256:330cc27ccbf7f1e992e69fef78261dc7c6569012cf397db8d3de0234e6c937ca"}, 315 | {file = "funcsigs-1.0.2.tar.gz", hash = "sha256:a7bb0f2cf3a3fd1ab2732cb49eba4252c2af4240442415b4abce3b87022a8f50"}, 316 | ] 317 | importlib-metadata = [ 318 | {file = "importlib_metadata-1.3.0-py2.py3-none-any.whl", hash = "sha256:d95141fbfa7ef2ec65cfd945e2af7e5a6ddbd7c8d9a25e66ff3be8e3daf9f60f"}, 319 | {file = "importlib_metadata-1.3.0.tar.gz", hash = "sha256:073a852570f92da5f744a3472af1b61e28e9f78ccf0c9117658dc32b15de7b45"}, 320 | ] 321 | more-itertools = [ 322 | {file = "more-itertools-5.0.0.tar.gz", hash = "sha256:38a936c0a6d98a38bcc2d03fdaaedaba9f412879461dd2ceff8d37564d6522e4"}, 323 | {file = "more_itertools-5.0.0-py2-none-any.whl", hash = "sha256:c0a5785b1109a6bd7fac76d6837fd1feca158e54e521ccd2ae8bfe393cc9d4fc"}, 324 | {file = "more_itertools-5.0.0-py3-none-any.whl", hash = "sha256:fe7a7cae1ccb57d33952113ff4fa1bc5f879963600ed74918f1236e212ee50b9"}, 325 | ] 326 | packaging = [ 327 | {file = "packaging-19.2-py2.py3-none-any.whl", hash = "sha256:d9551545c6d761f3def1677baf08ab2a3ca17c56879e70fecba2fc4dde4ed108"}, 328 | {file = "packaging-19.2.tar.gz", hash = "sha256:28b924174df7a2fa32c1953825ff29c61e2f5e082343165438812f00d3a7fc47"}, 329 | ] 330 | pathlib2 = [ 331 | {file = "pathlib2-2.3.5-py2.py3-none-any.whl", hash = "sha256:0ec8205a157c80d7acc301c0b18fbd5d44fe655968f5d947b6ecef5290fc35db"}, 332 | {file = "pathlib2-2.3.5.tar.gz", hash = "sha256:6cd9a47b597b37cc57de1c05e56fb1a1c9cc9fab04fe78c29acd090418529868"}, 333 | ] 334 | pluggy = [ 335 | {file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"}, 336 | {file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"}, 337 | ] 338 | py = [ 339 | {file = "py-1.8.0-py2.py3-none-any.whl", hash = "sha256:64f65755aee5b381cea27766a3a147c3f15b9b6b9ac88676de66ba2ae36793fa"}, 340 | {file = "py-1.8.0.tar.gz", hash = "sha256:dc639b046a6e2cff5bbe40194ad65936d6ba360b52b3c3fe1d08a82dd50b5e53"}, 341 | ] 342 | pycodestyle = [ 343 | {file = "pycodestyle-2.5.0-py2.py3-none-any.whl", hash = "sha256:95a2219d12372f05704562a14ec30bc76b05a5b297b21a5dfe3f6fac3491ae56"}, 344 | {file = "pycodestyle-2.5.0.tar.gz", hash = "sha256:e40a936c9a450ad81df37f549d676d127b1b66000a6c500caa2b085bc0ca976c"}, 345 | ] 346 | pyparsing = [ 347 | {file = "pyparsing-2.4.5-py2.py3-none-any.whl", hash = "sha256:20f995ecd72f2a1f4bf6b072b63b22e2eb457836601e76d6e5dfcd75436acc1f"}, 348 | {file = "pyparsing-2.4.5.tar.gz", hash = "sha256:4ca62001be367f01bd3e92ecbb79070272a9d4964dce6a48a82ff0b8bc7e683a"}, 349 | ] 350 | pytest = [ 351 | {file = "pytest-4.6.0-py2.py3-none-any.whl", hash = "sha256:5467f37a0d6bb0b4e684b71af268e005996b9eaaefe54e3d64d86afd90da8d78"}, 352 | {file = "pytest-4.6.0.tar.gz", hash = "sha256:52fa94b4ac81d2f063ee05e303acedf5c605e15dc0f4eef468b5c137f77241c3"}, 353 | ] 354 | rope = [ 355 | {file = "rope-0.14.0-py2-none-any.whl", hash = "sha256:6b728fdc3e98a83446c27a91fc5d56808a004f8beab7a31ab1d7224cecc7d969"}, 356 | {file = "rope-0.14.0-py3-none-any.whl", hash = "sha256:f0dcf719b63200d492b85535ebe5ea9b29e0d0b8aebeb87fe03fc1a65924fdaf"}, 357 | {file = "rope-0.14.0.tar.gz", hash = "sha256:c5c5a6a87f7b1a2095fb311135e2a3d1f194f5ecb96900fdd0a9100881f48aaf"}, 358 | ] 359 | scandir = [ 360 | {file = "scandir-1.10.0-cp27-cp27m-win32.whl", hash = "sha256:92c85ac42f41ffdc35b6da57ed991575bdbe69db895507af88b9f499b701c188"}, 361 | {file = "scandir-1.10.0-cp27-cp27m-win_amd64.whl", hash = "sha256:cb925555f43060a1745d0a321cca94bcea927c50114b623d73179189a4e100ac"}, 362 | {file = "scandir-1.10.0-cp34-cp34m-win32.whl", hash = "sha256:2c712840c2e2ee8dfaf36034080108d30060d759c7b73a01a52251cc8989f11f"}, 363 | {file = "scandir-1.10.0-cp34-cp34m-win_amd64.whl", hash = "sha256:2586c94e907d99617887daed6c1d102b5ca28f1085f90446554abf1faf73123e"}, 364 | {file = "scandir-1.10.0-cp35-cp35m-win32.whl", hash = "sha256:2b8e3888b11abb2217a32af0766bc06b65cc4a928d8727828ee68af5a967fa6f"}, 365 | {file = "scandir-1.10.0-cp35-cp35m-win_amd64.whl", hash = "sha256:8c5922863e44ffc00c5c693190648daa6d15e7c1207ed02d6f46a8dcc2869d32"}, 366 | {file = "scandir-1.10.0-cp36-cp36m-win32.whl", hash = "sha256:2ae41f43797ca0c11591c0c35f2f5875fa99f8797cb1a1fd440497ec0ae4b022"}, 367 | {file = "scandir-1.10.0-cp36-cp36m-win_amd64.whl", hash = "sha256:7d2d7a06a252764061a020407b997dd036f7bd6a175a5ba2b345f0a357f0b3f4"}, 368 | {file = "scandir-1.10.0-cp37-cp37m-win32.whl", hash = "sha256:67f15b6f83e6507fdc6fca22fedf6ef8b334b399ca27c6b568cbfaa82a364173"}, 369 | {file = "scandir-1.10.0-cp37-cp37m-win_amd64.whl", hash = "sha256:b24086f2375c4a094a6b51e78b4cf7ca16c721dcee2eddd7aa6494b42d6d519d"}, 370 | {file = "scandir-1.10.0.tar.gz", hash = "sha256:4d4631f6062e658e9007ab3149a9b914f3548cb38bfb021c64f39a025ce578ae"}, 371 | ] 372 | six = [ 373 | {file = "six-1.13.0-py2.py3-none-any.whl", hash = "sha256:1f1b7d42e254082a9db6279deae68afb421ceba6158efa6131de7b3003ee93fd"}, 374 | {file = "six-1.13.0.tar.gz", hash = "sha256:30f610279e8b2578cab6db20741130331735c781b56053c59c4076da27f06b66"}, 375 | ] 376 | toml = [ 377 | {file = "toml-0.10.0-py2.7.egg", hash = "sha256:f1db651f9657708513243e61e6cc67d101a39bad662eaa9b5546f789338e07a3"}, 378 | {file = "toml-0.10.0-py2.py3-none-any.whl", hash = "sha256:235682dd292d5899d361a811df37e04a8828a5b1da3115886b73cf81ebc9100e"}, 379 | {file = "toml-0.10.0.tar.gz", hash = "sha256:229f81c57791a41d65e399fc06bf0848bab550a9dfd5ed66df18ce5f05e73d5c"}, 380 | ] 381 | wcwidth = [ 382 | {file = "wcwidth-0.1.7-py2.py3-none-any.whl", hash = "sha256:f4ebe71925af7b40a864553f761ed559b43544f8f71746c2d756c7fe788ade7c"}, 383 | {file = "wcwidth-0.1.7.tar.gz", hash = "sha256:3df37372226d6e63e1b1e1eda15c594bca98a22d33a23832a90998faa96bc65e"}, 384 | ] 385 | zipp = [ 386 | {file = "zipp-0.6.0-py2.py3-none-any.whl", hash = "sha256:f06903e9f1f43b12d371004b4ac7b06ab39a44adc747266928ae6debfa7b3335"}, 387 | {file = "zipp-0.6.0.tar.gz", hash = "sha256:3718b1cbcd963c7d4c5511a8240812904164b7f381b647143a89d3b98f9bcd8e"}, 388 | ] 389 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "alfred-help-workflow" 3 | version = "1.6.0-alpha.0" 4 | description = "" 5 | authors = ["Alexander Kramarev "] 6 | 7 | [tool.poetry.dependencies] 8 | python = "^2.7" 9 | Alfred-Workflow = "^1.37.2" 10 | 11 | [tool.poetry.dev-dependencies] 12 | toml = "^0.10.0" 13 | pytest = "4.6" 14 | rope = "^0.14.0" 15 | autopep8 = "^1.4.4" 16 | 17 | [build-system] 18 | requires = ["poetry>=0.12"] 19 | build-backend = "poetry.masonry.api" 20 | -------------------------------------------------------------------------------- /src/alfred-2/info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | bundleid 6 | com.pochemuto.alfred.workflow.AlfredHelp 7 | category 8 | Tools 9 | connections 10 | 11 | 68637FD7-2E45-4403-B3E4-DD061FD0FF47 12 | 13 | 14 | destinationuid 15 | 786140ED-62A9-4C41-81E3-923FE306E61A 16 | modifiers 17 | 0 18 | modifiersubtext 19 | 20 | 21 | 22 | 23 | createdby 24 | pochemuto 25 | description 26 | List all alfred keywords 27 | disabled 28 | 29 | name 30 | Alfred Keywords 31 | objects 32 | 33 | 34 | config 35 | 36 | argumenttype 37 | 1 38 | escaping 39 | 102 40 | keyword 41 | ? 42 | queuedelaycustom 43 | 3 44 | queuedelayimmediatelyinitially 45 | 46 | queuedelaymode 47 | 0 48 | queuemode 49 | 1 50 | script 51 | python alfredhelp.py --keywords "{query}" 52 | title 53 | List all registered alfred keywords 54 | type 55 | 0 56 | withspace 57 | 58 | 59 | type 60 | alfred.workflow.input.scriptfilter 61 | uid 62 | 68637FD7-2E45-4403-B3E4-DD061FD0FF47 63 | version 64 | 0 65 | 66 | 67 | config 68 | 69 | concurrently 70 | 71 | escaping 72 | 68 73 | script 74 | tell application "Alfred 2" to search "{query}" 75 | type 76 | 6 77 | 78 | type 79 | alfred.workflow.action.script 80 | uid 81 | 786140ED-62A9-4C41-81E3-923FE306E61A 82 | version 83 | 0 84 | 85 | 86 | readme 87 | 88 | This workflow helps you remember the keyword. Just enter ? And the name of the action and you will see a list of available actions. 89 | 90 | uidata 91 | 92 | 68637FD7-2E45-4403-B3E4-DD061FD0FF47 93 | 94 | ypos 95 | 10.0 96 | 97 | 786140ED-62A9-4C41-81E3-923FE306E61A 98 | 99 | ypos 100 | 10.0 101 | 102 | 103 | version 104 | unspecified 105 | webaddress 106 | https://github.com/pochemuto/alfred-help-workflow 107 | 108 | 109 | -------------------------------------------------------------------------------- /src/alfred-3/info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | bundleid 6 | com.pochemuto.alfred.workflow.AlfredHelp 7 | category 8 | Tools 9 | connections 10 | 11 | 68637FD7-2E45-4403-B3E4-DD061FD0FF47 12 | 13 | 14 | destinationuid 15 | 786140ED-62A9-4C41-81E3-923FE306E61A 16 | modifiers 17 | 0 18 | modifiersubtext 19 | 20 | 21 | 22 | 23 | createdby 24 | pochemuto 25 | description 26 | List all alfred keywords 27 | disabled 28 | 29 | name 30 | Alfred Keywords 31 | objects 32 | 33 | 34 | config 35 | 36 | argumenttype 37 | 1 38 | escaping 39 | 102 40 | keyword 41 | ? 42 | queuedelaycustom 43 | 3 44 | queuedelayimmediatelyinitially 45 | 46 | queuedelaymode 47 | 0 48 | queuemode 49 | 1 50 | script 51 | python alfredhelp.py --keywords "{query}" 52 | title 53 | List all registered alfred keywords 54 | type 55 | 0 56 | withspace 57 | 58 | 59 | type 60 | alfred.workflow.input.scriptfilter 61 | uid 62 | 68637FD7-2E45-4403-B3E4-DD061FD0FF47 63 | version 64 | 0 65 | 66 | 67 | config 68 | 69 | concurrently 70 | 71 | escaping 72 | 68 73 | script 74 | tell application "Alfred 3" to search "{query}" 75 | type 76 | 6 77 | 78 | type 79 | alfred.workflow.action.script 80 | uid 81 | 786140ED-62A9-4C41-81E3-923FE306E61A 82 | version 83 | 0 84 | 85 | 86 | readme 87 | 88 | This workflow helps you remember the keyword. Just enter ? And the name of the action and you will see a list of available actions. 89 | 90 | uidata 91 | 92 | 68637FD7-2E45-4403-B3E4-DD061FD0FF47 93 | 94 | ypos 95 | 10.0 96 | 97 | 786140ED-62A9-4C41-81E3-923FE306E61A 98 | 99 | ypos 100 | 10.0 101 | 102 | 103 | version 104 | unspecified 105 | webaddress 106 | https://github.com/pochemuto/alfred-help-workflow 107 | 108 | 109 | -------------------------------------------------------------------------------- /src/main/68637FD7-2E45-4403-B3E4-DD061FD0FF47.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pochemuto/alfred-help-workflow/653f5185e8dc2bba75aaf5a45f8f4523aa6f52e2/src/main/68637FD7-2E45-4403-B3E4-DD061FD0FF47.png -------------------------------------------------------------------------------- /src/main/alfredhelp.py: -------------------------------------------------------------------------------- 1 | #coding: utf 2 | __author__ = u'pochemuto' 3 | import sys, plistlib, os, operator 4 | from os import path 5 | from workflow import Workflow, ICON_HELP, ICON_INFO 6 | from workflow.background import run_in_background, is_running 7 | 8 | CACHE_MAX_AGE = 12 * 60 * 60 # 12 hours 9 | log = None 10 | 11 | 12 | def main(wf): 13 | args = Args(wf.args) 14 | 15 | actions = wf.cached_data('actions', None, max_age=0) 16 | 17 | if wf.update_available: 18 | # Add a notification to top of Script Filter results 19 | wf.add_item(u'New version available', 20 | u'Action this item to install the update', 21 | autocomplete='workflow:update', 22 | icon=ICON_INFO) 23 | 24 | if not wf.cached_data_fresh('actions', max_age=CACHE_MAX_AGE): 25 | cmd = ['/usr/bin/python', wf.workflowfile('alfredhelp.py'), '--scan'] 26 | run_in_background(u'scan', cmd) 27 | 28 | if is_running(u'scan'): 29 | wf.add_item( 30 | title=u'Scanning alfred workflows...', 31 | valid=False, 32 | icon=ICON_INFO 33 | ) 34 | 35 | if args.show_keywords and actions: 36 | # Alphabetize initial results by keyword. 37 | actions = sorted(actions, key=operator.attrgetter('keyword')) 38 | 39 | if args.query: 40 | actions = wf.filter(args.query, actions, key=search_key, min_score=20) 41 | 42 | for action in actions: 43 | argument = action.keyword 44 | if action.add_space: 45 | argument += u' ' 46 | wf.add_item( 47 | title=u'{keyword} - {title}'.format(keyword=action.keyword, title=action.title), 48 | subtitle=action.subtitle, 49 | icon=action.icon, 50 | arg=argument, 51 | valid=True 52 | ) 53 | 54 | elif args.scan: 55 | def get_posts(): 56 | return scan(path.join(wf.alfred_env['preferences'], 'workflows')) 57 | 58 | wf.cached_data('actions', get_posts, max_age=CACHE_MAX_AGE) 59 | 60 | wf.send_feedback() 61 | return 0 62 | 63 | 64 | class Action: 65 | def __init__(self): 66 | self.icon = None 67 | self.keyword = None 68 | self.title = None 69 | self.subtitle = None 70 | self.workflow_name = None 71 | self.add_space = False 72 | 73 | class Args: 74 | def __init__(self, args): 75 | self.show_keywords = self.get_arg(args, 0) == '--keywords' 76 | self.scan = self.get_arg(args, 0) == '--scan' 77 | self.query = self.get_arg(args, 1) 78 | 79 | @staticmethod 80 | def get_arg(args, n, default=None): 81 | return args[n] if len(args) > n else default 82 | 83 | def search_key(action): 84 | elements = [action.keyword, action.title, action.subtitle] 85 | elements = filter(lambda n: n is not None, elements) 86 | return u' '.join(elements) 87 | 88 | 89 | def read_info(info_file): 90 | items = [] 91 | plist = plistlib.readPlist(info_file) 92 | if 'disabled' in plist and plist['disabled']: 93 | return [] 94 | wf_name = plist['name'] 95 | wf_path = path.dirname(info_file) 96 | for object in plist['objects']: 97 | if 'config' in object and 'keyword' in object['config']: 98 | config = object['config'] 99 | 100 | action = Action() 101 | action.workflow_name = wf_name 102 | action.keyword = config['keyword'] 103 | action.add_space = 'argumenttype' in config and config['argumenttype'] in [0, 1] and config['withspace'] 104 | 105 | action_icon = path.join(wf_path, object['uid']) + '.png' 106 | main_icon = path.join(wf_path, 'icon') + '.png' 107 | if path.isfile(action_icon): 108 | action.icon = action_icon 109 | elif path.isfile(main_icon): 110 | action.icon = main_icon 111 | else: 112 | action.icon = ICON_HELP 113 | 114 | if 'title' in config: 115 | action.title = config['title'] 116 | elif 'text' in config: 117 | action.title = config['text'] 118 | else: 119 | action.title = wf_name 120 | 121 | action.subtitle = wf_name if wf_name != action.title else None 122 | 123 | items.append(action) 124 | return items 125 | 126 | 127 | def scan(workflows_dir): 128 | log.debug('scanning {0}'.format(workflows_dir)) 129 | items = [] 130 | for wf_dir in os.listdir(workflows_dir): 131 | info_file = path.join(workflows_dir, wf_dir, 'info.plist') 132 | if path.isfile(info_file): 133 | items.extend(read_info(info_file)) 134 | 135 | return items 136 | 137 | if __name__ == '__main__': 138 | wf = Workflow(update_settings={ 139 | 'github_slug': 'pochemuto/alfred-help-workflow' 140 | }) 141 | log = wf.logger 142 | sys.exit(wf.run(main)) 143 | -------------------------------------------------------------------------------- /src/main/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pochemuto/alfred-help-workflow/653f5185e8dc2bba75aaf5a45f8f4523aa6f52e2/src/main/icon.png -------------------------------------------------------------------------------- /src/main/info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | bundleid 6 | com.pochemuto.alfred.workflow.AlfredHelp 7 | category 8 | Tools 9 | connections 10 | 11 | 68637FD7-2E45-4403-B3E4-DD061FD0FF47 12 | 13 | 14 | destinationuid 15 | 786140ED-62A9-4C41-81E3-923FE306E61A 16 | modifiers 17 | 0 18 | modifiersubtext 19 | 20 | 21 | 22 | 23 | createdby 24 | pochemuto 25 | description 26 | List all alfred keywords 27 | disabled 28 | 29 | name 30 | Alfred Keywords 31 | objects 32 | 33 | 34 | config 35 | 36 | argumenttype 37 | 1 38 | escaping 39 | 102 40 | keyword 41 | ? 42 | queuedelaycustom 43 | 3 44 | queuedelayimmediatelyinitially 45 | 46 | queuedelaymode 47 | 0 48 | queuemode 49 | 1 50 | script 51 | python alfredhelp.py --keywords "{query}" 52 | title 53 | List all registered alfred keywords 54 | type 55 | 0 56 | withspace 57 | 58 | 59 | type 60 | alfred.workflow.input.scriptfilter 61 | uid 62 | 68637FD7-2E45-4403-B3E4-DD061FD0FF47 63 | version 64 | 0 65 | 66 | 67 | config 68 | 69 | concurrently 70 | 71 | escaping 72 | 68 73 | script 74 | tell application "Alfred 4" to search "{query}" 75 | type 76 | 6 77 | 78 | type 79 | alfred.workflow.action.script 80 | uid 81 | 786140ED-62A9-4C41-81E3-923FE306E61A 82 | version 83 | 0 84 | 85 | 86 | readme 87 | 88 | This workflow helps you remember the keyword. Just enter ? And the name of the action and you will see a list of available actions. 89 | 90 | uidata 91 | 92 | 68637FD7-2E45-4403-B3E4-DD061FD0FF47 93 | 94 | ypos 95 | 10.0 96 | 97 | 786140ED-62A9-4C41-81E3-923FE306E61A 98 | 99 | ypos 100 | 10.0 101 | 102 | 103 | version 104 | unspecified 105 | webaddress 106 | https://github.com/pochemuto/alfred-help-workflow 107 | 108 | 109 | --------------------------------------------------------------------------------