├── .github
└── ISSUE_TEMPLATE
│ ├── bug_report.yml
│ ├── config.yml
│ └── feature_suggestion.yml
├── LICENSE
├── README.md
├── Resources
└── find-dicts.swift
└── Workflow
├── find-dicts
├── icon.png
├── images
└── about
│ ├── asdicm.png
│ └── newdict.png
└── info.plist
/.github/ISSUE_TEMPLATE/bug_report.yml:
--------------------------------------------------------------------------------
1 | name: Bug Report
2 | description: File a bug report
3 | body:
4 | - type: input
5 | attributes:
6 | label: Workflow version
7 | description: Open the Workflow in Alfred Preferences and find it at the top, near the description
8 | validations:
9 | required: true
10 | - type: input
11 | attributes:
12 | label: Alfred version
13 | description: In the top left corner of Alfred Preferences → General
14 | validations:
15 | required: true
16 | - type: input
17 | attributes:
18 | label: macOS version
19 | description: Click on the menubar → About This Mac
20 | validations:
21 | required: true
22 | - type: textarea
23 | attributes:
24 | label: Debugger output
25 | description: Perform the failing action with [the debugger](https://www.alfredapp.com/help/workflows/advanced/debugger/) open
26 | render: alfred_debugger
27 | validations:
28 | required: true
29 | - type: textarea
30 | attributes:
31 | label: More details
32 | description: Explain what you did, what happened, and what you expected to happen
33 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: false
2 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_suggestion.yml:
--------------------------------------------------------------------------------
1 | name: Feature Suggestion
2 | description: Suggest a new feature
3 | body:
4 | - type: textarea
5 | attributes:
6 | label: Feature details
7 | description: Explain the feature idea
8 | validations:
9 | required: true
10 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | BSD 3-Clause License
2 |
3 | Copyright (c) 2021, Running with Crayons Ltd
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, are permitted provided that the following conditions are met:
8 |
9 | 1. Redistributions of source code must retain the above copyright notice, this
10 | list of conditions and the following disclaimer.
11 |
12 | 2. Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | 3. Neither the name of the copyright holder nor the names of its
17 | contributors may be used to endorse or promote products derived from
18 | this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | #
AppleScript Dictionaries Alfred Workflow
2 |
3 | Find and open Mac automation dictionaries
4 |
5 | [⤓ Install on the Alfred Gallery](https://alfred.app/workflows/alfredapp/applescript-dictionaries)
6 |
7 | ## Usage
8 |
9 | Search through installed AppleScript dictionaries via the `asdic` keyword. ↩︎ to open.
10 |
11 | 
12 |
13 | A minority of apps use an older dictionary format which can be converted with the [Universal Action](https://www.alfredapp.com/help/features/universal-actions/).
14 |
15 | 
16 |
--------------------------------------------------------------------------------
/Resources/find-dicts.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | // Helpers
4 | struct ScriptFilter: Codable {
5 | let cache: Cache
6 | let items: [Item]
7 |
8 | struct Cache: Codable {
9 | let seconds: Int
10 | let loosereload: Bool
11 | }
12 |
13 | struct Item: Codable {
14 | let uid: String
15 | let title: String
16 | let subtitle: String
17 | let type: String
18 | let icon: FileIcon
19 | let arg: String
20 |
21 | struct FileIcon: Codable {
22 | let path: String
23 | let type: String
24 | }
25 | }
26 | }
27 |
28 | func findDict(inFolder: URL) -> URL? {
29 | let resourcesFolder = inFolder.appendingPathComponent("Contents/Resources")
30 |
31 | return try? FileManager.default.contentsOfDirectory(
32 | at: resourcesFolder, includingPropertiesForKeys: nil, options: .skipsHiddenFiles
33 | ).first(where: { $0.pathExtension == "sdef" })
34 | }
35 |
36 | // Find apps with Spotlight
37 | let spotQuery = "kMDItemContentTypeTree == 'com.apple.application-bundle'"
38 | let searchQuery = MDQueryCreate(kCFAllocatorDefault, spotQuery as CFString, nil, nil)
39 |
40 | MDQueryExecute(searchQuery, CFOptionFlags(kMDQuerySynchronous.rawValue))
41 | let resultCount = MDQueryGetResultCount(searchQuery)
42 |
43 | let spotApps: [URL] = (0...fromOpaque(rawPointer!).takeUnretainedValue()
46 |
47 | guard let resultPath = MDItemCopyAttribute(resultItem, kMDItemPath) as? String else { return nil }
48 | return URL(fileURLWithPath: resultPath)
49 | }
50 |
51 | // Find apps in special locations
52 | let additions: [URL] = [
53 | URL(fileURLWithPath: "/System/Library/ScriptingAdditions/StandardAdditions.osax")
54 | ]
55 |
56 | let customApps: [URL] = {
57 | guard let workflowData = ProcessInfo.processInfo.environment["alfred_workflow_data"] else { return [] }
58 | let dataFolder = URL(fileURLWithPath: workflowData)
59 |
60 | guard
61 | let dataContents = try? FileManager.default.contentsOfDirectory(
62 | at: dataFolder, includingPropertiesForKeys: nil, options: .skipsHiddenFiles)
63 | else { return [] }
64 |
65 | return dataContents.filter { $0.pathExtension == "app" }
66 | }()
67 |
68 | // Join all apps
69 | let allApps = spotApps + additions + customApps
70 |
71 | // Structure JSON
72 | let cachingItems = ScriptFilter.Cache(seconds: 300, loosereload: true)
73 |
74 | let sfItems: [ScriptFilter.Item] = allApps.compactMap { app in
75 | guard let dict = findDict(inFolder: app)?.path else { return nil }
76 |
77 | return ScriptFilter.Item(
78 | uid: dict,
79 | title: app.deletingPathExtension().lastPathComponent,
80 | subtitle: dict,
81 | type: "file",
82 | icon: ScriptFilter.Item.FileIcon(path: app.path, type: "fileicon"),
83 | arg: dict
84 | )
85 | }
86 |
87 | // Output JSON
88 | let jsonData = try JSONEncoder().encode(ScriptFilter(cache: cachingItems, items: sfItems))
89 | print(String(data: jsonData, encoding: .utf8)!)
90 |
--------------------------------------------------------------------------------
/Workflow/find-dicts:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alfredapp/applescript-dictionaries-workflow/31b596714f87a67af5fd283ef91b22474a7ce56f/Workflow/find-dicts
--------------------------------------------------------------------------------
/Workflow/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alfredapp/applescript-dictionaries-workflow/31b596714f87a67af5fd283ef91b22474a7ce56f/Workflow/icon.png
--------------------------------------------------------------------------------
/Workflow/images/about/asdicm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alfredapp/applescript-dictionaries-workflow/31b596714f87a67af5fd283ef91b22474a7ce56f/Workflow/images/about/asdicm.png
--------------------------------------------------------------------------------
/Workflow/images/about/newdict.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alfredapp/applescript-dictionaries-workflow/31b596714f87a67af5fd283ef91b22474a7ce56f/Workflow/images/about/newdict.png
--------------------------------------------------------------------------------
/Workflow/info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | bundleid
6 | com.alfredapp.vitor.applescriptdictionaries
7 | connections
8 |
9 | 0C34FB83-CBAA-41E0-B482-47270F6ABB19
10 |
11 |
12 | destinationuid
13 | 7307CF18-FA86-41AF-BDC7-AB66D75667E9
14 | modifiers
15 | 0
16 | modifiersubtext
17 |
18 | sourceoutputuid
19 | 2304F28F-1CCF-4DE4-B47C-14A637B2551D
20 | vitoclose
21 |
22 |
23 |
24 | destinationuid
25 | 8F720020-3637-4681-926C-B434F10BCF70
26 | modifiers
27 | 0
28 | modifiersubtext
29 |
30 | vitoclose
31 |
32 |
33 |
34 | 7307CF18-FA86-41AF-BDC7-AB66D75667E9
35 |
36 | 7A58F92F-50C1-456F-90EA-BE0F47F2C5A4
37 |
38 |
39 | destinationuid
40 | D912659A-805F-410F-A602-8BA6AC894BEF
41 | modifiers
42 | 0
43 | modifiersubtext
44 |
45 | vitoclose
46 |
47 |
48 |
49 | 7D4ED081-C6A3-4262-9578-229B307CE081
50 |
51 |
52 | destinationuid
53 | 99D694BC-7C8B-4735-A22C-21F9CAAE5A54
54 | modifiers
55 | 0
56 | modifiersubtext
57 |
58 | vitoclose
59 |
60 |
61 |
62 | 8F720020-3637-4681-926C-B434F10BCF70
63 |
64 |
65 | destinationuid
66 | 27798F6D-1A31-4878-B7F9-CCB14F11A67F
67 | modifiers
68 | 0
69 | modifiersubtext
70 |
71 | vitoclose
72 |
73 |
74 |
75 | 99D694BC-7C8B-4735-A22C-21F9CAAE5A54
76 |
77 | D912659A-805F-410F-A602-8BA6AC894BEF
78 |
79 |
80 | destinationuid
81 | 0C34FB83-CBAA-41E0-B482-47270F6ABB19
82 | modifiers
83 | 0
84 | modifiersubtext
85 |
86 | vitoclose
87 |
88 |
89 |
90 |
91 | createdby
92 | Vítor Galvão
93 | description
94 | Find and open Mac automation dictionaries
95 | disabled
96 |
97 | name
98 | AppleScript Dictionaries
99 | objects
100 |
101 |
102 | config
103 |
104 | concurrently
105 |
106 | escaping
107 | 102
108 | script
109 | open -a 'Script Editor' "${1}"
110 | scriptargtype
111 | 1
112 | scriptfile
113 |
114 | type
115 | 11
116 |
117 | type
118 | alfred.workflow.action.script
119 | uid
120 | 99D694BC-7C8B-4735-A22C-21F9CAAE5A54
121 | version
122 | 2
123 |
124 |
125 | config
126 |
127 | alfredfiltersresults
128 |
129 | alfredfiltersresultsmatchmode
130 | 0
131 | argumenttreatemptyqueryasnil
132 |
133 | argumenttrimmode
134 | 0
135 | argumenttype
136 | 1
137 | escaping
138 | 102
139 | keyword
140 | {var:search_keyword}
141 | queuedelaycustom
142 | 3
143 | queuedelayimmediatelyinitially
144 |
145 | queuedelaymode
146 | 0
147 | queuemode
148 | 1
149 | runningsubtext
150 | Searching for AppleScript dictionaries…
151 | script
152 |
153 | scriptargtype
154 | 1
155 | scriptfile
156 | find-dicts
157 | skipuniversalaction
158 |
159 | subtext
160 |
161 | title
162 | AppleScript Dictionaries
163 | type
164 | 8
165 | withspace
166 |
167 |
168 | type
169 | alfred.workflow.input.scriptfilter
170 | uid
171 | 7D4ED081-C6A3-4262-9578-229B307CE081
172 | version
173 | 3
174 |
175 |
176 | config
177 |
178 | concurrently
179 |
180 | escaping
181 | 68
182 | script
183 | tell application id "com.runningwithcrayons.Alfred" to reload workflow (system attribute "alfred_workflow_bundleid")
184 | scriptargtype
185 | 1
186 | scriptfile
187 |
188 | type
189 | 6
190 |
191 | type
192 | alfred.workflow.action.script
193 | uid
194 | 7307CF18-FA86-41AF-BDC7-AB66D75667E9
195 | version
196 | 2
197 |
198 |
199 | config
200 |
201 | lastpathcomponent
202 |
203 | onlyshowifquerypopulated
204 |
205 | removeextension
206 |
207 | text
208 | Please ensure the app has an AppleScript dictionary
209 | title
210 | Failed to Generate Dictionary
211 |
212 | type
213 | alfred.workflow.output.notification
214 | uid
215 | 8F720020-3637-4681-926C-B434F10BCF70
216 | version
217 | 1
218 |
219 |
220 | config
221 |
222 | soundname
223 | Sosumi
224 | systemsound
225 |
226 |
227 | type
228 | alfred.workflow.output.playsound
229 | uid
230 | 27798F6D-1A31-4878-B7F9-CCB14F11A67F
231 | version
232 | 1
233 |
234 |
235 | config
236 |
237 | acceptsmulti
238 | 0
239 | filetypes
240 |
241 | com.apple.application-bundle
242 |
243 | name
244 | Generate AppleScript Dictionary
245 |
246 | type
247 | alfred.workflow.trigger.action
248 | uid
249 | 7A58F92F-50C1-456F-90EA-BE0F47F2C5A4
250 | version
251 | 1
252 |
253 |
254 | config
255 |
256 | concurrently
257 |
258 | escaping
259 | 102
260 | script
261 | ObjC.import("AppKit")
262 |
263 | // Helpers
264 | function envVar(varName) {
265 | return $.NSProcessInfo
266 | .processInfo
267 | .environment
268 | .objectForKey(varName).js
269 | }
270 |
271 | function writeFile(path, text) {
272 | $(text).writeToFileAtomicallyEncodingError(path, true, $.NSUTF8StringEncoding, undefined)
273 | }
274 |
275 | function mkdir(path) {
276 | $.NSFileManager
277 | .defaultManager
278 | .createDirectoryAtPathWithIntermediateDirectoriesAttributesError(path, true, undefined, undefined)
279 | }
280 |
281 | function runCommand(...arguments) {
282 | const task = $.NSTask.alloc.init
283 | const stdout = $.NSPipe.pipe
284 |
285 | task.executableURL = $.NSURL.fileURLWithPath("/usr/bin/env")
286 | task.arguments = arguments
287 | task.standardOutput = stdout
288 | task.launchAndReturnError(false)
289 |
290 | const dataOut = stdout.fileHandleForReading.readDataToEndOfFileAndReturnError(false)
291 | const stringOut = $.NSString.alloc.initWithDataEncoding(dataOut, $.NSUTF8StringEncoding).js
292 |
293 | return stringOut
294 | }
295 |
296 | // Main
297 | function run(argv) {
298 | // Get info
299 | const appPath = argv[0]
300 | const appName = Application(appPath).name()
301 | const appDict = runCommand("/usr/bin/sdef", appPath)
302 |
303 | // Exit if failed to generate dictionary
304 | if (appDict.length === 0) return false
305 |
306 | // Store dictionary in custom directory tree
307 | const shimDir = `${envVar("alfred_workflow_data")}/${appName}`
308 | const dictDir = `${shimDir}/Contents/Resources`
309 | mkdir(dictDir)
310 | writeFile(`${dictDir}/${appName}.sdef`, appDict)
311 |
312 | // Change folder icon to match app
313 | const workspace = $.NSWorkspace.sharedWorkspace
314 | const icon = workspace.iconForFile(appPath)
315 | workspace.setIconForFileOptions(icon, shimDir, 0)
316 |
317 | // Exit with success
318 | return true
319 | }
320 | scriptargtype
321 | 1
322 | scriptfile
323 |
324 | type
325 | 7
326 |
327 | type
328 | alfred.workflow.action.script
329 | uid
330 | D912659A-805F-410F-A602-8BA6AC894BEF
331 | version
332 | 2
333 |
334 |
335 | config
336 |
337 | conditions
338 |
339 |
340 | inputstring
341 |
342 | matchcasesensitive
343 |
344 | matchmode
345 | 5
346 | matchstring
347 |
348 | outputlabel
349 | Success
350 | uid
351 | 2304F28F-1CCF-4DE4-B47C-14A637B2551D
352 |
353 |
354 | elselabel
355 | Failure
356 | hideelse
357 |
358 |
359 | type
360 | alfred.workflow.utility.conditional
361 | uid
362 | 0C34FB83-CBAA-41E0-B482-47270F6ABB19
363 | version
364 | 1
365 |
366 |
367 | readme
368 | ## Usage
369 |
370 | Search through installed AppleScript dictionaries via the `asdic` keyword. <kbd>↩</kbd> to open.
371 |
372 | 
373 |
374 | A minority of apps use an older dictionary format which can be converted with the [Universal Action](https://www.alfredapp.com/help/features/universal-actions/).
375 |
376 | 
377 | uidata
378 |
379 | 0C34FB83-CBAA-41E0-B482-47270F6ABB19
380 |
381 | xpos
382 | 455
383 | ypos
384 | 315
385 |
386 | 27798F6D-1A31-4878-B7F9-CCB14F11A67F
387 |
388 | xpos
389 | 750
390 | ypos
391 | 295
392 |
393 | 7307CF18-FA86-41AF-BDC7-AB66D75667E9
394 |
395 | note
396 | Flush cache
397 | xpos
398 | 575
399 | ypos
400 | 115
401 |
402 | 7A58F92F-50C1-456F-90EA-BE0F47F2C5A4
403 |
404 | note
405 | Generate sdef for app with older scriptSuite
406 | xpos
407 | 45
408 | ypos
409 | 295
410 |
411 | 7D4ED081-C6A3-4262-9578-229B307CE081
412 |
413 | note
414 | List AppleScript dictionaries
415 | xpos
416 | 45
417 | ypos
418 | 115
419 |
420 | 8F720020-3637-4681-926C-B434F10BCF70
421 |
422 | xpos
423 | 575
424 | ypos
425 | 295
426 |
427 | 99D694BC-7C8B-4735-A22C-21F9CAAE5A54
428 |
429 | note
430 | Open dictionary
431 | xpos
432 | 265
433 | ypos
434 | 115
435 |
436 | D912659A-805F-410F-A602-8BA6AC894BEF
437 |
438 | note
439 | Build sdef for app
440 | xpos
441 | 265
442 | ypos
443 | 295
444 |
445 |
446 | userconfigurationconfig
447 |
448 |
449 | config
450 |
451 | default
452 | asdic
453 | placeholder
454 |
455 | required
456 |
457 | trim
458 |
459 |
460 | description
461 |
462 | label
463 | Search Keyword
464 | type
465 | textfield
466 | variable
467 | search_keyword
468 |
469 |
470 | version
471 | 2024.1
472 | webaddress
473 | https://github.com/alfredapp/applescript-dictionaries-workflow/
474 |
475 |
476 |
--------------------------------------------------------------------------------