# PopClip Extension Development β Complete Documentation
> Every page of PopClip's extension developer docs, concatenated into
> one file. Individual pages are at the source URLs given below. The
> TypeScript type definitions for the JavaScript API and config format are
> at https://www.popclip.app/dev/popclip.d.ts.
---
# π€ PopClip Extensions Developer Documentation
> Source: https://www.popclip.app/dev/index.md
This section of the website provides a detailed specification of PopClip's
extension system. With this information, you can create your own
extensions.
**Tip: Getting help**
If you have any questions about the specification or need help with developing
an extension, I encourage you to post to the
[PopClip Forum](https://forum.popclip.app). I frequently check the forum and
will be happy to help you there.
**Note: Markdown for LLMs**
Every page here has a plain Markdown twin β add `.md` to its URL. The whole
reference is in one file at [/dev/all.md](https://www.popclip.app/dev/all.md); see also
[/llms.txt](https://www.popclip.app/llms.txt).
## Extensions Overview
### Snippets and Packages
A PopClip extension can be either a [snippet](https://www.popclip.app/dev/snippets.md) or a
[package](https://www.popclip.app/dev/packages.md). The following table summarizes the differences:
| | Snippet | Package |
| --------------- | ----------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- |
| What is it? | Plain text in YAML format. | A folder containing a config file plus other files such as icons, source files, and a readme file. |
| Install method | PopClip can load it directly from a text selection. | Double-clicking it will open it in PopClip. |
| Distribution | Can be copied and pasted as text, e.g. on forums, pastebins, etc. | Can be downloaded as a file. |
| Signing | Not signed. | Can be signed. |
| Advantages | Easy to create and informally share. No need for separate files. | Easy for end user to install. Allows modular source code with complex functionality. |
| Disadvantages | Limited to what can be done with a single text file. | More complex to create. Steeper learning curve. |
| File extensions | None (direct selection)
`.popcliptxt` (text file) | `.popclipext` (folder)
`.popclipextz` (zipped folder) |
### Types of actions
An extension defines one or more actions. Each action can be one of seven
types. Three are script types, which run code that you provide:
| Action Type | Description |
| ----------------------------------------- | -------------------------------------- |
| [JavaScript](https://www.popclip.app/dev/js-actions.md) | Run a JavaScript or TypeScript script. |
| [AppleScript](https://www.popclip.app/dev/applescript-actions.md) | Run an AppleScript script. |
| [Shell Script](https://www.popclip.app/dev/shell-script-actions.md) | Run a shell script. |
JavaScript is the recommended script type. JavaScript actions have full access
to PopClip's [JavaScript environment](https://www.popclip.app/dev/js-environment.md), and a
[module-based extension](https://www.popclip.app/dev/js-modules.md) can define everything it does in
JavaScript or TypeScript. Use the AppleScript and Shell Script types only when
the job can't be done with JavaScript alone.
The other four types are ready-made conveniences for performing common tasks,
with no code needed:
| Action Type | Description |
| ----------------------------------- | ------------------------------------------------------- |
| [URL](https://www.popclip.app/dev/url-actions.md) | Open a URL, with the selected text inserted as a query. |
| [Key Press](https://www.popclip.app/dev/key-press-actions.md) | Press a key combination. |
| [Service](https://www.popclip.app/dev/service-actions.md) | Send the selected text to a macOS Service. |
| [Shortcut](https://www.popclip.app/dev/shortcut-actions.md) | Send the selected text to a macOS Shortcut. |
## Extension signing
Please be aware that PopClip extensions can contain arbitrary executable code.
Be careful about the extensions you create, and be wary about loading extensions
you get from elsewhere.
PopClip extension packages published in the [directory](https://www.popclip.app/extensions/) are
digitally signed. PopClip will install signed extensions without showing any
warning to the user.
If you create your own extension, it will be unsigned. If an unsigned extension
contains Shell Script actions or AppleScript actions, or has entitlements,
PopClip will display a warning dialog when you try to install it:

## Development environment
You can create extensions using any text editor. The macOS-included app TextEdit
will suffice for simple snippets, but otherwise, I recommend using a dedicated
code editor such as [VS Code](https://code.visualstudio.com/),
[Sublime Text](https://www.sublimetext.com/),
[BBEdit](https://www.barebones.com/products/bbedit/), or
[Nova](https://nova.app/).
### Type definitions
The complete TypeScript definitions for PopClip's JavaScript API are published
as a single file:
[**popclip.d.ts**](https://www.popclip.app/dev/popclip.d.ts)
As well as the `popclip` object and other globals available to scripts, this
file describes the extension config format itself β see the `ActionProperties`,
`Extension`, `Option` and `Requirement` types. Point your editor at it for
autocomplete and type checking, or give it to an AI coding assistant as a
complete reference for writing extensions.
The same definitions are available as the
[`@popclip/types`](https://www.npmjs.com/package/@popclip/types) npm package,
and browsable as HTML in the
[JavaScript API Reference](https://www.popclip.app/dev/api/).
### Turn off unsigned warning
If the unsigned extension warning gets annoying while you test your work, you
can turn it off. Run the following command at the Terminal, then Quit and
restart PopClip:
`defaults write com.pilotmoon.popclip LoadUnsignedExtensions -bool YES`
And if you are working on fixing an extension with the `com.pilotmoon.`
identifier prefix:
`defaults write com.pilotmoon.popclip AllowUnsignedReservedPrefixes -bool YES`
### Debug output
To help you when creating extensions, PopClip can send script outputs and other
debug info to the Console app. To enable it, run this command in Terminal, then
Quit and restart PopClip:
`defaults write com.pilotmoon.popclip EnableExtensionDebug -bool YES`
You can then view the debug output in the Console app.

To filter the Console to show just PopClip extensions, enter Process "PopClip"
and Category "Extension" in the Search field.
You can add this as a saved search by clicking the Save button in the toolbar:

## Show off your work
If you create an extension that others might find useful, you are welcome to
submit it for publication in the
[PopClip Extensions Directory](https://www.popclip.app/extensions/). See
[Submit an Extension](https://www.popclip.app/extensions/submit.md) for how it works.
---
# Snippets
> Source: https://www.popclip.app/dev/snippets.md
A snippet is the simplest kind of PopClip extension, because it is just plain
text. PopClip can load a snippet directly from a text selection, without the
need for separate files or folders.
## Example
It is easiest to start with an example:
```yaml
#popclip
name: Urban Dictionary
icon: UD
url: https://www.urbandictionary.com/define.php?term=***
```
When you select whole block of text above, PopClip will detect the snippet and
offer an "Install Extension" action.

## Format
A snippet always begins with `#popclip` (or `#Β popclip`) and can be up to 5000
characters long. It is parsed as [YAML 1.2](https://yaml.org/spec/1.2.2/). The
body of the snippet defines the extension's [config dictionary](https://www.popclip.app/dev/config.md).
**Tip: Commments in snippets**
Note that `#` begins a YAML comment. Thus the entire snippet including the
`#popclip` line parses as valid YAML.
## Creating snippets
PopClip will display any errors it encounters while trying to load the snippet
in the PopClip bar itself.

In the absence of an `identifier` field, the `name` acts as the identifier for
the extension. Installing a snippet with the same name as an existing snippet
will replace it.
A snippet can do everything that a [package](https://www.popclip.app/dev/packages.md) extension can do. The
only limitation is that it can't refer to any external files.
## More examples
A [Shortcuts](https://www.popclip.app/dev/shortcut-actions.md) example:
```yaml
# popclip shortcuts example
name: Run My Shortcut
icon: symbol:moon.stars # Apple SF Symbols
macos version: '12.0' # shortcuts only work on Monterey and above!
shortcut name: My Shortcut Name
```
A [Service](https://www.popclip.app/dev/service-actions.md) example (this time using flow-style YAML markup,
with braces):
```yaml
#popclip service example
{ name: Stickies, service name: Make Sticky }
```
A [Key Press](https://www.popclip.app/dev/key-press-actions.md) example:
```yaml
#popclip key press example
name: Key Press Example
key combo: command option J
```
An [shell script](https://www.popclip.app/dev/shell-script-actions.md) example:
```yaml
#popclip shellscript example
name: Say
interpreter: zsh
shell script: say -v Daniel $POPCLIP_TEXT
```
A [JavaScript](https://www.popclip.app/dev/js-actions.md) example, including multiple actions:
```yaml
#popclip js + multi action example
name: Markdown Formatting
requirements: [text, paste]
actions:
- title: Markdown Bold # note: actions have a `title`, not a `name`
icon: circle filled B
javascript: popclip.pasteText('**' + popclip.input.text + '**')
- title: Markdown Italic
icon: circle filled I
javascript: popclip.pasteText('*' + popclip.input.text + '*')
```
```json
#popclip js + multi action example
{
"name": "Markdown Formatting",
"requirements": [
"text",
"paste"
],
"actions": [
{
"title": "Markdown Bold",
"icon": "circle filled B",
"javascript": "popclip.pasteText('**' + popclip.input.text + '**')"
},
{
"title": "Markdown Italic",
"icon": "circle filled I",
"javascript": "popclip.pasteText('*' + popclip.input.text + '*')"
}
]
}
```
**Warning: #1 rule of YAML: Do not indent with tabs!**
When writing snippets in YAML with indented parts, as in the example above, do
not use tabs for indenting. YAML does not allow it β use spaces instead.
## Inverted syntax
PopClip also supports an "inside out" snippet syntax, which looks like this:
```javascript
// #popclip
// name: Hello JS
// icon: Hi!
// language: javascript
const greeting = "Hello " + popclip.input.text;
popclip.showText(greeting);
```
This method, which I call **inverted syntax**, offers several benefits: we get
code syntax highlighting and autocomplete from our text editor, and we don't
have to indent the script awkwardly in the YAML.
The inverted syntax is supported for JavaScript, AppleScript and shell script
actions.
When using the inverted syntax, the whole text of the snippet becomes the
`javascript file`, `module`, `applescript file` or `shell script file` for the
extension. The config header should be added using the appropriate comment style
for the source language (see [examples](#inverted-syntax-examples) below).
**Note: When to use inverted syntax?**
Inverted syntax is most useful when the script is multiple lines long, or when
you want to take advantage of the language syntax highlighting and autocomplete
features of your text editor.
### Inverted syntax config
When using the inverted syntax, the whole snippet text will be interpreted as if
it was a file specified in the root of the config, as follows:
| To intepret as... | Include these fields... |
| ------------------- | --------------------------------------------------------------------------------- |
| `shell script file` | Specify `interpreter` string. |
| `applescript file` | Specify `language: applescript`. |
| `javascript file` | Specify `language: javascript` or `language: typescript` and omit `module` field. |
| `module` | Specify `language: javascript` or `language: typescript` with `module: true`.
|
### Inverted syntax examples
Here is a Python example:
```python
# #popclip
# { name: Hello Python, icon: hi, after: show-result, interpreter: python3 }
import os
print('Hello, ' + os.environ['POPCLIP_TEXT'] + '!', end='')
```
An alternative way to specify a shell script's interpreter is to put a shebang
(`#!`) line at the top, in which case, the `interpreter` field is not needed:
```python
#!/usr/bin/env python3
# #popclip
# { name: Hello Python 2, icon: hi, after: show-result }
import os
print('Hello again, ' + os.environ['POPCLIP_TEXT'] + '!', end='')
```
An AppleScript example:
```applescript
-- # PopClip LaunchBar example
-- { name: LaunchBar, icon: LB, language: applescript }
tell application "LaunchBar"
set selection to "{popclip text}"
end tell
```
## `.popcliptxt` files
You can save a snippet to a plain text file with a `.popcliptxt` extension. When
you double-click such a file in Finder, PopClip will load the snippet from the
file and install it. There is no size limit on the snippet when installed by
this method.
## Further examples
There are lots of snippet examples posted in the
[PopClip Forum](https://forum.popclip.app/). Here are a few interesting ones
that demonstrate various techniques:
- [Markdown highlighting](https://forum.popclip.app/t/markdown-highlighting/556)
- [A PopClip Extension for ChatGPT](https://forum.popclip.app/t/a-popclip-extension-for-chatgpt/1283)
- [Text-to-speech with Azure API](https://forum.popclip.app/t/new-snippet-azure-text-to-speech/1790)
- [Search DuchDuckGo in DuckDuckGo Browser](https://forum.popclip.app/t/snippet-search-duckduckgo-in-duckduckgo-browser/1763)
- [S p a c e d w o r d s](https://forum.popclip.app/t/s-p-a-c-e-d-w-o-r-d-s/1705)
---
# Packages
> Source: https://www.popclip.app/dev/packages.md
A PopClip extension package bundles together all the files needed for an
extension in a folder.
## The package folder
A PopClip extension package consists of a config file plus (optional) additional
files such as icons and scripts, all contained in a directory whose name ends
with `.popclipext`.
When you double-click a `.popclipext` package, macOS will open it with PopClip,
which will attempt to load and install it.
**Tip: Viewing package contents**
macOS treats `.popclipext`directories as packages. To view the contents of a
package, right-click it in Finder and choose Show Package Contents.
Here is an example package structure, the
[Say](https://github.com/pilotmoon/PopClip-Extensions/tree/master/source/Say.popclipext)
extension:
```
Say.popclipext/ -- Package folder
β
βββ Config.json -- Config file
βββ README.md -- Readme file
βββ say.zsh -- Script file
βββ speechicon.png -- Icon file
```
### Zipped `.popclipextz` files
For distribution, an extension package folder may be zipped and renamed with the
extension `.popclipextz`. You can examine an existing PopClip extension by
renaming it with a `.zip` extension and unzipping it, to reveal a `.popclipext`
package.
## The Config file
Every package must include a [config dictionary](https://www.popclip.app/dev/config.md). PopClip will try
looking in the root of the package directory for a file with base name `Config`
(case sensitive). The file is interpreted according to its extension:
| File Name | Format | Interpretation |
| ----------------------------------------- | ---------------------- | ------------------------------------------------------------------------------- |
| `Config.plist` | Plist | An Apple [XML Property List](https://en.wikipedia.org/wiki/Property_list) file. |
| `Config.json` | JSON | A [JSON](https://www.json.org/json-en.html) file. |
| `Config.yaml` | YAML | A [YAML 1.2](https://yaml.org) file. |
| `Config.js`, `Config.ts` | JavaScript, TypeScript | [JavaScript or TypeScript module](https://www.popclip.app/dev/js-modules.md). |
| `Config.` or just `Config` | Snippet | Interpreted as [snippet](https://www.popclip.app/dev/snippets.md). |
**Note: Historical note**
Plist was the original format for PopClip extensions, and many of the older
extensions in [pilotmoon/PopClip-Extensions](https://github.com/pilotmoon/PopClip-Extensions)
are in Plist format. I recommend avoiding Plist for new extensions, as it is
verbose and harder to read and edit than JSON or YAML.
## Other files
Apart from the config file, an extension package may contain any number of other
files. You are free to name these however you like, except for the reserved
names `Config[.*]` and `_Signature.plist`. You can also use subfolders to
organise your files.
## Examples
For a whole bunch of example extension packages,
see [pilotmoon/PopClip-Extensions/.../source](https://github.com/pilotmoon/PopClip-Extensions/tree/master/source).
---
# Config
> Source: https://www.popclip.app/dev/config.md
Every extension is defined by a configuration dictionary. This can be provided either
by a [snippet](https://www.popclip.app/dev/snippets.md) or a [package](https://www.popclip.app/dev/packages.md), but in each case the
underlying structure is the same.
**Tip: Key names**
PopClip is very flexible about how you name keys. In this documentation you'll
mostly see keys named in lowercase with spaces, for example `key name`. However,
PopClip will treat `Key Name`, `keyName`, `KeyName`, `key_name`, `key-name` and
`KEY_NAME` as equivalents.
I tend to use `key name` in YAML, and `keyName` in JSON, but you can use
whatever you prefer.
## Example
Before diving in to the details, let's look at an example config dictionary for
a published extension. This is based on the
[Yoink extension](https://github.com/pilotmoon/PopClip-Extensions/tree/master/source/Yoink.popclipext):
```json
{
"identifier": "at.EternalStorms.Yoink.PopClipExtension",
"popclipVersion": 3785,
"name": "Yoink",
"icon": "yoink.png",
"app": {
"name": "Yoink",
"link": "https://eternalstorms.at/yoink/mac",
"checkInstalled": true,
"bundleIdentifiers": [
"at.EternalStorms.Yoink",
"at.EternalStorms.Yoink-setapp",
"at.EternalStorms.Yoink-demo"
]
},
"serviceName": "Add Selected Text to Yoink",
"captureHtml": true,
"description": "Add the selected text to Yoink."
}
```
```yaml
identifier: at.EternalStorms.Yoink.PopClipExtension
popclip version: 3785
name: Yoink
icon: yoink.png
app:
name: Yoink
link: https://eternalstorms.at/yoink/mac
check installed: true
bundle identifiers:
- at.EternalStorms.Yoink
- at.EternalStorms.Yoink-setapp
- at.EternalStorms.Yoink-demo
service name: Add Selected Text to Yoink
capture html: true
description: Add the selected text to Yoink.
```
Not all of those fields are strictly needed. As we have already seen in
[Snippets](https://www.popclip.app/dev/snippets.md), we can also express a similar extension very
minimally, at the loss of some of the niceties that the fleshed-out version
provides:
```json
{
"name": "Yoink",
"serviceName": "Add Selected Text to Yoink"
}
```
```yaml
name: Yoink
service name: Add Selected Text to Yoink
```
**Tip: Minimal or maximal?**
In general, if you're writing an extension for your own use, you can freely omit
any fields that you don't need. But if you're preparing an extension for
publication, you should flesh out the config as much as possible, to provide the
best user experience for your extension.
## Top level properties
The following keys are used at the top level of the config to define properties
of the extension itself. All properties are optional except `name`.
| Key | Type | Description |
| --------------------------- | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name` (Required) | String (Localizable) | A short, human-readable display name for this extension. |
| `icon` | String | See [Icons](https://www.popclip.app/dev/icons.md). If you omit this field, the icon for the first action will be used (if any), or else no icon will be displayed. |
| `identifier` | String | You may provide a string to uniquely identify this extension. See [The `identifier` field](#the-identifier-field). |
| `description` | String (Localizable) | A short, human readable description of this extension. Appears in the [directory](https://www.popclip.app/extensions/) but not in the app. |
| `keywords` | String | Space-separated words to help people find your extension in the [directory](https://www.popclip.app/extensions/), whose search matches case-insensitively against the name and keywords but not the description. |
| `macos version` | String | Minimum version number of Mac OS X needed by this extension. For example `10.8.2` or `11.0`. |
| `popclip version` | Integer | Minimum PopClip version required. This is the integer build number e.g. `4151`. Specifying the current PopClip version here can help preserve your extension's functionality in future, because PopClip applies backward-compatibility rules for old extensions. |
| `options` | Array | Array of dictionaries defining the options for this extension, if any. See [The `options` array](#the-options-array). |
| `entitlements` | Array | Only applies to JavaScript extensions. The possible values are `network` (allows use of XMLHttpRequest), `dynamic` (allows dynamically generated actions) and `script` (allows use of `popclip.runAppleScript()` and `popclip.runAppleScriptFile()`). |
| `action` or `actions` | Dictionary or Array | A dictionary or array of dictionaries defining the action(s) for this extension. See [Actions](https://www.popclip.app/dev/actions.md). |
| `submenu` | Array | Makes the extension a single button that opens a submenu of child actions. See [Submenus](https://www.popclip.app/dev/actions.md#submenus). |
| `show as` | String | Sets the default presentation of the extension's actions in the PopClip bar: `icon` or `text`. If omitted, the default is `icon`. (The user can override this per action.) |
| `auth service label` | String (Localizable) | For extensions with a sign-in (`auth` function): a label identifying the service to which the user is being asked to sign in. Used in UI prompts like _Sign in to your [label] account_. If omitted, the extension name is used. |
| `offers multiple instances` | Boolean | Controls whether PopClip enables the Duplicate and New Instance commands for this extension. By default, PopClip allows multiple instances if the action has any options. Setting this property will override the automatic behavior. |
| `shell script rationale` | String | A brief explanation of why the extension needs a [Shell Script action](https://www.popclip.app/dev/shell-script-actions.md) instead of JavaScript. Not used by the app; required when [submitting](https://www.popclip.app/extensions/submit.md#shell-script-policy) an extension with a Shell Script action to the directory. |
### The `identifier` field
An identifier may contain only alphanumeric characters (`A-Z`, `a-z`, `0-9`),
period (`.`), and hyphen (`-`).
A good identifier should be globally unique so as not to clash with other
creators. Use your own prefix, which could be a reverse DNS-style prefix based
on a domain name you control, such as `com.example.myextension`. Alternatively,
just pick something likely to be unique to you.
If you don't provide an `identifier`, PopClip will identify the extension by the
package directory name (e.g. `Name.popclipext`) if it's a package extension, or
the `name` if it's a snippet.
**Warning: Reserved identifier**
The identifier prefix `com.pilotmoon.` is reserved for signed extensions
published by me. If you try to use it for your own extensions, you'll get an
error.
### The `options` array
Options are presented to the user in a preferences user interface window and are
saved in PopClip's preferences on behalf of the extension. Options appear in the
UI in the order they appear in the `options` array. An option dictionary has the
following structure.
| Key | Type | Required? | Description |
| --------------- | -------------------- | ---------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `identifier` | String | Required | Identifying string for this option. This is passed to your script. The identifier will be downcased or upcased for AppleScript and Shell Script targets, respectively β see [Script variables](https://www.popclip.app/dev/script-variables.md). |
| `type` | String | Required | See [Option types](#option-types). |
| `label` | String (Localizable) | Optional | The label to appear in the UI for this option. If omitted, the identifier is displayed. |
| `description` | String (Localizable) | Optional | A longer description to appear in the UI to explain this option. May contain clickable links, written either as bare URLs or in Markdown syntax: `[label](https://example.com)`. |
| `default value` | String | Optional | This field specifies the default value of the option. If omitted, `string` options default to the empty string, `boolean` options default to `true`, and `multiple` options default to the top item in the list. A `secret` field may not have a default value. |
| `values` | Array | Required for `multiple` type | Array of strings representing the possible values for the multiple choice option. |
| `value labels` | Array | Optional | Array of "human friendly" strings corresponding to the multiple choice values. This is used only in the PopClip options UI, and is not passed to the script. If omitted, the option values themselves are shown. |
| `inset` | Boolean | Optional | If true, the option field will be shown inset to the right of the label, instead of under it. Default is false. |
| `icon` | String | Optional | For `boolean` options only. Specify an icon to appear next to the check box. |
| `multiline` | Boolean | Optional | For `string` options only. If true, shows a multi-line text field instead of a single-line one. Useful for longer inputs such as prompts. Default is false. |
| `allow other` | Boolean | Optional | For `multiple` options only. If true, adds an "Otherβ¦" choice to the list, allowing the user to enter a free-text value. Default is false. |
| `allow none` | Boolean | Optional | For `multiple` options only. If true, adds a "None" choice to the list, whose value is the empty string. Default is false. |
#### Option types
The `type` field of an option dictionary can be one of the following:
| Type | Description |
| ---------- | ------------------------------------------------------------------------- |
| `string` | A text field. |
| `boolean` | A checkbox. |
| `multiple` | A multiple choice list. An array of `values` strings must be provided. |
| `secret` | Concealed text entry. The value is persisted in the keychain. |
| `heading` | Shows as a text heading in the settings user interface. Carries no value. |
## Config notes
### Localized strings
Fields shown as "String (Localizable)" type may be either a string or a
dictionary. If you supply a string, that string is always used. Alternatively,
you can supply a dictionary mapping language codes to strings, and PopClip will
display the string for the user's preferred language if possible, with fallback
to the `en` string, which is always required.
The following language codes are supported:
**Language codes table**
| Language Code | Language Name |
| ------------- | --------------------- |
| `en` | English |
| `en-gb` | English (UK) |
| `da` | Danish |
| `de` | German |
| `es` | Spanish |
| `fr` | French |
| `it` | Italian |
| `ja` | Japanese |
| `ko` | Korean |
| `nl` | Dutch |
| `pl` | Polish |
| `pt-br` | Portuguese (BR) |
| `ru` | Russian |
| `sk` | Slovak |
| `tr` | Turkish |
| `vi` | Vietnamese |
| `zh-hans` | Chinese (Simplified) |
| `zh-hant` | Chinese (Traditional) |
**Note: Example of localized string**
```yaml
name:
en: My Extension
fr: Mon Extension
zh-hans: ζηζ©ε±
```
### Null values in Plist
Plist does not have a native way to represent the `null` value of JSON and YAML.
Use `` in a Plist where you would use `null` in JSON or YAML.
### Key name mapping
Some field names were different in older versions of PopClip. Others have
alternative allowable spellings.
To preserve backwards compatibility, key names in the config are transformed as
follows:
1. First, the naming convention is standardized to lowercase with spaces. For
example, `RequiredApps` becomes `required apps`.
2. Then, if the field name has the prefix `extension` or `option` (which were
expected by older versions of PopClip), it is removed.
3. Finally, PopClip applies the following mapping:
**Key name mapping table**
| Alternative name | Canonical name |
| ------------------------- | ---------------- |
| apple script | applescript |
| apple script call | applescript call |
| apple script file | applescript file |
| blocked apps | excluded apps |
| flip horizontal | flip x |
| flip vertical | flip y |
| id | identifier |
| image file | icon |
| java script | javascript |
| java script file | javascript file |
| js | javascript |
| lang | language |
| mac os version | macos version |
| params | parameters |
| pass html | capture html |
| pop clip version | popclip version |
| preserve image color | preserve color |
| regular expression | regex |
| required os version | macos version |
| required software version | popclip version |
| script interpreter | interpreter |
**Note: Example**
An old extension uses the key `Extension Image File` to define its icon. PopClip
will first standardize the case to `extension image file`. Then it will remove
the `extension` prefix, leaving `image file`. Then it will map this to `icon`.
---
# Icons
> Source: https://www.popclip.app/dev/icons.md
Icons are specified by using a text string to describe an icon.
_(An interactive icon preview tool is available in the [online version of this page](https://www.popclip.app/dev/icons.md).)_
An icon specifier string describes an icon using a simple text-based format. The
string consists of a series of space-separated keywords, with the final keyword
specifying the **base icon** (see [Base icon formats](#base-icon-formats)), and
the preceding keywords (if any) specifying **modifiers** (see
[Icon modifiers](#icon-modifiers)).
Here are some examples:
| Specifier string | Icon generated | Notes |
| -------------------------------- | ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
| `T` | | Here, `T` specifies the base icon as a [text icon](#text-icons). |
| `square T` | | Here, `square` is a modifier that encloses the base icon in a square. |
| `square filled T` | | Combining two modifiers; `filled` specifies that the square is a solid shape. |
| `circle filled T` | | Here we use a non-Ascii character as the base icon. The `circle` modifier encloses the base icon in a circle. |
| `search filled T` | | The `search` modifier encloses the base icon in a magnifying glass shape. |
| `iconify:mdi:home` | | Here, the base icon is an [Iconify icon](#iconify-icons). |
| `square filled iconify:mdi:home` | | We put the home icon in a filled square. |
| `strike iconify:mdi:home` | | The `strike` modifier draws a strike-through line over the base icon. |
| `symbol:hand.raised` | | Here, the base icon as an [SF Symbols icon](#sf-symbols-icons). |
| `flip-x symbol:hand.raised` | | The `flip-x` modifier flips the base icon horizontally. |
## Base icon formats
### File icons
File icons can only be used in [packages](https://www.popclip.app/dev/packages.md). The icon is specified
as a path to a `.png` or `.svg` image file in the package.
```json
{
"icon": "icon.png"
}
```
A good icon will feature a monochrome shape on a transparent background.
Variable opacity can be used for shading. PNG icons should be at least 256
pixels high.
**Note: File icons with modifiers**
File icons can be used with modifiers by adding the prefix `file:`, for example:
```
{
"icon": "strike file:icon.png"
}
```
### Text icons
Text icons can include up to 3 characters and are specified as the text itself.
The prefix `text:` can optionally be used.
```json
{
"icon": "T"
}
```
Text icons are drawn using the system font. Adding the `monospaced` modifier
will draw the icon in a monospaced variant.
If the text icon is a single emoji without modifiers, it rendered in color.
Examples:
| Specifier string | Icon generated |
| --------------------- | ----------------------------- |
| `ABC` (or `text:ABC`) | |
| `@` | |
| `ζ¬` | |
| `()` | |
| `monospaced ()` | |
| `π΅βπ«` | |
**Note: π‘ Tip: Monospaced font**
Punctuation symbols often look better in icons when drawn with the `monospaced`
modifier.
### Iconify icons
[Iconify](https://iconify.design/) provides access to over 200,000 icons from a
variety of open-source icon sets, using a unified naming system.
The Iconify website provides a [catalog](https://icon-sets.iconify.design/) of
available icons.
The format is `iconify::`.
Some Iconify icons contain color information. These are automatically recognized
by PopClip and will be rendered in color.
Examples:
| Specifier string | Icon generated |
| ---------------------------- | ------------------------------------------ |
| `iconify:ion:fish` | |
| `iconify:solar:flag-bold` | |
| `iconify:logos:spotify-icon` | |
### SF Symbols icons
Apple [SF Symbols](https://developer.apple.com/sf-symbols/) are available on
macOS 11.0 and above. (Symbol availability may vary by macOS version). The icon
catalog can be viewed by installing Apple's SF Symbols app on your Mac.
The format is `symbol:`.
Symbols are always drawn in the monochrome variant.
Examples:
| Specifier string | Icon generated |
| ----------------------- | -------------------------------------------- |
| `symbol:flame` | |
| `symbol:hand.raised` | |
| `symbol:signpost.right` | |
### SVG Icons
The icon string can supply SVG source code for an icon. The format is `svg: