|
@@ -7,21 +7,20 @@
|
|
|
# Created on 2016-06-25
|
|
|
#
|
|
|
|
|
|
-"""
|
|
|
-:class:`Workflow3` supports Alfred 3's new features.
|
|
|
-
|
|
|
-It is an Alfred 3-only version of :class:`~workflow.workflow.Workflow`.
|
|
|
+"""An Alfred 3+ version of :class:`~workflow.Workflow`.
|
|
|
|
|
|
-It supports setting :ref:`workflow-variables` and
|
|
|
-:class:`the more advanced modifiers <Modifier>` supported by Alfred 3.
|
|
|
+:class:`~workflow.Workflow3` supports new features, such as
|
|
|
+setting :ref:`workflow-variables` and
|
|
|
+:class:`the more advanced modifiers <Modifier>` supported by Alfred 3+.
|
|
|
|
|
|
In order for the feedback mechanism to work correctly, it's important
|
|
|
to create :class:`Item3` and :class:`Modifier` objects via the
|
|
|
:meth:`Workflow3.add_item()` and :meth:`Item3.add_modifier()` methods
|
|
|
respectively. If you instantiate :class:`Item3` or :class:`Modifier`
|
|
|
-objects directly, the current :class:`~workflow.workflow3.Workflow3`
|
|
|
-object won't be aware of them, and they won't be sent to Alfred when
|
|
|
-you call :meth:`~workflow.workflow3.Workflow3.send_feedback()`.
|
|
|
+objects directly, the current :class:`Workflow3` object won't be aware
|
|
|
+of them, and they won't be sent to Alfred when you call
|
|
|
+:meth:`Workflow3.send_feedback()`.
|
|
|
+
|
|
|
"""
|
|
|
|
|
|
from __future__ import print_function, unicode_literals, absolute_import
|
|
@@ -30,44 +29,151 @@ import json
|
|
|
import os
|
|
|
import sys
|
|
|
|
|
|
-from .workflow import Workflow
|
|
|
+from .workflow import ICON_WARNING, Workflow
|
|
|
|
|
|
|
|
|
-class Modifier(object):
|
|
|
- """Modify ``Item3`` values for when specified modifier keys are pressed.
|
|
|
+class Variables(dict):
|
|
|
+ """Workflow variables for Run Script actions.
|
|
|
+
|
|
|
+ .. versionadded: 1.26
|
|
|
+
|
|
|
+ This class allows you to set workflow variables from
|
|
|
+ Run Script actions.
|
|
|
+
|
|
|
+ It is a subclass of :class:`dict`.
|
|
|
+
|
|
|
+ >>> v = Variables(username='deanishe', password='hunter2')
|
|
|
+ >>> v.arg = u'output value'
|
|
|
+ >>> print(v)
|
|
|
+
|
|
|
+ See :ref:`variables-run-script` in the User Guide for more
|
|
|
+ information.
|
|
|
+
|
|
|
+ Args:
|
|
|
+ arg (unicode, optional): Main output/``{query}``.
|
|
|
+ **variables: Workflow variables to set.
|
|
|
+
|
|
|
+
|
|
|
+ Attributes:
|
|
|
+ arg (unicode): Output value (``{query}``).
|
|
|
+ config (dict): Configuration for downstream workflow element.
|
|
|
+
|
|
|
+ """
|
|
|
+
|
|
|
+ def __init__(self, arg=None, **variables):
|
|
|
+ """Create a new `Variables` object."""
|
|
|
+ self.arg = arg
|
|
|
+ self.config = {}
|
|
|
+ super(Variables, self).__init__(**variables)
|
|
|
+
|
|
|
+ @property
|
|
|
+ def obj(self):
|
|
|
+ """Return ``alfredworkflow`` `dict`."""
|
|
|
+ o = {}
|
|
|
+ if self:
|
|
|
+ d2 = {}
|
|
|
+ for k, v in self.items():
|
|
|
+ d2[k] = v
|
|
|
+ o['variables'] = d2
|
|
|
+
|
|
|
+ if self.config:
|
|
|
+ o['config'] = self.config
|
|
|
+
|
|
|
+ if self.arg is not None:
|
|
|
+ o['arg'] = self.arg
|
|
|
+
|
|
|
+ return {'alfredworkflow': o}
|
|
|
+
|
|
|
+ def __unicode__(self):
|
|
|
+ """Convert to ``alfredworkflow`` JSON object.
|
|
|
+
|
|
|
+ Returns:
|
|
|
+ unicode: ``alfredworkflow`` JSON object
|
|
|
+
|
|
|
+ """
|
|
|
+ if not self and not self.config:
|
|
|
+ if self.arg:
|
|
|
+ return self.arg
|
|
|
+ else:
|
|
|
+ return u''
|
|
|
+
|
|
|
+ return json.dumps(self.obj)
|
|
|
+
|
|
|
+ def __str__(self):
|
|
|
+ """Convert to ``alfredworkflow`` JSON object.
|
|
|
+
|
|
|
+ Returns:
|
|
|
+ str: UTF-8 encoded ``alfredworkflow`` JSON object
|
|
|
+
|
|
|
+ """
|
|
|
+ return unicode(self).encode('utf-8')
|
|
|
|
|
|
- Valid modifiers (i.e. values for ``key``) are:
|
|
|
|
|
|
- * cmd
|
|
|
- * alt
|
|
|
- * shift
|
|
|
- * ctrl
|
|
|
- * fn
|
|
|
+class Modifier(object):
|
|
|
+ """Modify :class:`Item3` arg/icon/variables when modifier key is pressed.
|
|
|
+
|
|
|
+ Don't use this class directly (as it won't be associated with any
|
|
|
+ :class:`Item3`), but rather use :meth:`Item3.add_modifier()`
|
|
|
+ to add modifiers to results.
|
|
|
+
|
|
|
+ >>> it = wf.add_item('Title', 'Subtitle', valid=True)
|
|
|
+ >>> it.setvar('name', 'default')
|
|
|
+ >>> m = it.add_modifier('cmd')
|
|
|
+ >>> m.setvar('name', 'alternate')
|
|
|
+
|
|
|
+ See :ref:`workflow-variables` in the User Guide for more information
|
|
|
+ and :ref:`example usage <example-variables>`.
|
|
|
+
|
|
|
+ Args:
|
|
|
+ key (unicode): Modifier key, e.g. ``"cmd"``, ``"alt"`` etc.
|
|
|
+ subtitle (unicode, optional): Override default subtitle.
|
|
|
+ arg (unicode, optional): Argument to pass for this modifier.
|
|
|
+ valid (bool, optional): Override item's validity.
|
|
|
+ icon (unicode, optional): Filepath/UTI of icon to use
|
|
|
+ icontype (unicode, optional): Type of icon. See
|
|
|
+ :meth:`Workflow.add_item() <workflow.Workflow.add_item>`
|
|
|
+ for valid values.
|
|
|
|
|
|
Attributes:
|
|
|
arg (unicode): Arg to pass to following action.
|
|
|
+ config (dict): Configuration for a downstream element, such as
|
|
|
+ a File Filter.
|
|
|
+ icon (unicode): Filepath/UTI of icon.
|
|
|
+ icontype (unicode): Type of icon. See
|
|
|
+ :meth:`Workflow.add_item() <workflow.Workflow.add_item>`
|
|
|
+ for valid values.
|
|
|
key (unicode): Modifier key (see above).
|
|
|
subtitle (unicode): Override item subtitle.
|
|
|
valid (bool): Override item validity.
|
|
|
variables (dict): Workflow variables set by this modifier.
|
|
|
+
|
|
|
"""
|
|
|
|
|
|
- def __init__(self, key, subtitle=None, arg=None, valid=None):
|
|
|
+ def __init__(self, key, subtitle=None, arg=None, valid=None, icon=None,
|
|
|
+ icontype=None):
|
|
|
"""Create a new :class:`Modifier`.
|
|
|
|
|
|
- You probably don't want to use this class directly, but rather
|
|
|
- use :meth:`Item3.add_modifier()` to add modifiers to results.
|
|
|
+ Don't use this class directly (as it won't be associated with any
|
|
|
+ :class:`Item3`), but rather use :meth:`Item3.add_modifier()`
|
|
|
+ to add modifiers to results.
|
|
|
|
|
|
Args:
|
|
|
key (unicode): Modifier key, e.g. ``"cmd"``, ``"alt"`` etc.
|
|
|
subtitle (unicode, optional): Override default subtitle.
|
|
|
arg (unicode, optional): Argument to pass for this modifier.
|
|
|
valid (bool, optional): Override item's validity.
|
|
|
+ icon (unicode, optional): Filepath/UTI of icon to use
|
|
|
+ icontype (unicode, optional): Type of icon. See
|
|
|
+ :meth:`Workflow.add_item() <workflow.Workflow.add_item>`
|
|
|
+ for valid values.
|
|
|
+
|
|
|
"""
|
|
|
self.key = key
|
|
|
self.subtitle = subtitle
|
|
|
self.arg = arg
|
|
|
self.valid = valid
|
|
|
+ self.icon = icon
|
|
|
+ self.icontype = icontype
|
|
|
|
|
|
self.config = {}
|
|
|
self.variables = {}
|
|
@@ -78,6 +184,7 @@ class Modifier(object):
|
|
|
Args:
|
|
|
name (unicode): Name of variable.
|
|
|
value (unicode): Value of variable.
|
|
|
+
|
|
|
"""
|
|
|
self.variables[name] = value
|
|
|
|
|
@@ -90,6 +197,7 @@ class Modifier(object):
|
|
|
|
|
|
Returns:
|
|
|
unicode or ``default``: Value of variable if set or ``default``.
|
|
|
+
|
|
|
"""
|
|
|
return self.variables.get(name, default)
|
|
|
|
|
@@ -99,6 +207,7 @@ class Modifier(object):
|
|
|
|
|
|
Returns:
|
|
|
dict: Modifier for serializing to JSON.
|
|
|
+
|
|
|
"""
|
|
|
o = {}
|
|
|
|
|
@@ -111,44 +220,63 @@ class Modifier(object):
|
|
|
if self.valid is not None:
|
|
|
o['valid'] = self.valid
|
|
|
|
|
|
- # Variables and config
|
|
|
- if self.variables or self.config:
|
|
|
- d = {}
|
|
|
- if self.variables:
|
|
|
- d['variables'] = self.variables
|
|
|
-
|
|
|
- if self.config:
|
|
|
- d['config'] = self.config
|
|
|
+ if self.variables:
|
|
|
+ o['variables'] = self.variables
|
|
|
|
|
|
- if self.arg is not None:
|
|
|
- d['arg'] = self.arg
|
|
|
+ if self.config:
|
|
|
+ o['config'] = self.config
|
|
|
|
|
|
- o['arg'] = json.dumps({'alfredworkflow': d})
|
|
|
+ icon = self._icon()
|
|
|
+ if icon:
|
|
|
+ o['icon'] = icon
|
|
|
|
|
|
return o
|
|
|
|
|
|
+ def _icon(self):
|
|
|
+ """Return `icon` object for item.
|
|
|
+
|
|
|
+ Returns:
|
|
|
+ dict: Mapping for item `icon` (may be empty).
|
|
|
+
|
|
|
+ """
|
|
|
+ icon = {}
|
|
|
+ if self.icon is not None:
|
|
|
+ icon['path'] = self.icon
|
|
|
+
|
|
|
+ if self.icontype is not None:
|
|
|
+ icon['type'] = self.icontype
|
|
|
+
|
|
|
+ return icon
|
|
|
+
|
|
|
|
|
|
class Item3(object):
|
|
|
- """Represents a feedback item for Alfred 3.
|
|
|
+ """Represents a feedback item for Alfred 3+.
|
|
|
|
|
|
Generates Alfred-compliant JSON for a single item.
|
|
|
|
|
|
- You probably shouldn't use this class directly, but via
|
|
|
- :meth:`Workflow3.add_item`. See :meth:`~Workflow3.add_item`
|
|
|
- for details of arguments.
|
|
|
+ Don't use this class directly (as it then won't be associated with
|
|
|
+ any :class:`Workflow3 <workflow.Workflow3>` object), but rather use
|
|
|
+ :meth:`Workflow3.add_item() <workflow.Workflow3.add_item>`.
|
|
|
+ See :meth:`~workflow.Workflow3.add_item` for details of arguments.
|
|
|
+
|
|
|
"""
|
|
|
|
|
|
def __init__(self, title, subtitle='', arg=None, autocomplete=None,
|
|
|
- valid=False, uid=None, icon=None, icontype=None,
|
|
|
+ match=None, valid=False, uid=None, icon=None, icontype=None,
|
|
|
type=None, largetext=None, copytext=None, quicklookurl=None):
|
|
|
- """Use same arguments as for :meth:`Workflow.add_item`.
|
|
|
+ """Create a new :class:`Item3` object.
|
|
|
+
|
|
|
+ Use same arguments as for
|
|
|
+ :class:`Workflow.Item <workflow.Workflow.Item>`.
|
|
|
|
|
|
Argument ``subtitle_modifiers`` is not supported.
|
|
|
+
|
|
|
"""
|
|
|
self.title = title
|
|
|
self.subtitle = subtitle
|
|
|
self.arg = arg
|
|
|
self.autocomplete = autocomplete
|
|
|
+ self.match = match
|
|
|
self.valid = valid
|
|
|
self.uid = uid
|
|
|
self.icon = icon
|
|
@@ -182,10 +310,12 @@ class Item3(object):
|
|
|
|
|
|
Returns:
|
|
|
unicode or ``default``: Value of variable if set or ``default``.
|
|
|
+
|
|
|
"""
|
|
|
return self.variables.get(name, default)
|
|
|
|
|
|
- def add_modifier(self, key, subtitle=None, arg=None, valid=None):
|
|
|
+ def add_modifier(self, key, subtitle=None, arg=None, valid=None, icon=None,
|
|
|
+ icontype=None):
|
|
|
"""Add alternative values for a modifier key.
|
|
|
|
|
|
Args:
|
|
@@ -193,14 +323,19 @@ class Item3(object):
|
|
|
subtitle (unicode, optional): Override item subtitle.
|
|
|
arg (unicode, optional): Input for following action.
|
|
|
valid (bool, optional): Override item validity.
|
|
|
+ icon (unicode, optional): Filepath/UTI of icon.
|
|
|
+ icontype (unicode, optional): Type of icon. See
|
|
|
+ :meth:`Workflow.add_item() <workflow.Workflow.add_item>`
|
|
|
+ for valid values.
|
|
|
|
|
|
Returns:
|
|
|
Modifier: Configured :class:`Modifier`.
|
|
|
+
|
|
|
"""
|
|
|
- mod = Modifier(key, subtitle, arg, valid)
|
|
|
+ mod = Modifier(key, subtitle, arg, valid, icon, icontype)
|
|
|
|
|
|
- for k in self.variables:
|
|
|
- mod.setvar(k, self.variables[k])
|
|
|
+ # Add Item variables to Modifier
|
|
|
+ mod.variables.update(self.variables)
|
|
|
|
|
|
self.modifiers[key] = mod
|
|
|
|
|
@@ -212,13 +347,14 @@ class Item3(object):
|
|
|
|
|
|
Returns:
|
|
|
dict: Data suitable for Alfred 3 feedback.
|
|
|
- """
|
|
|
- # Basic values
|
|
|
- o = {'title': self.title,
|
|
|
- 'subtitle': self.subtitle,
|
|
|
- 'valid': self.valid}
|
|
|
|
|
|
- icon = {}
|
|
|
+ """
|
|
|
+ # Required values
|
|
|
+ o = {
|
|
|
+ 'title': self.title,
|
|
|
+ 'subtitle': self.subtitle,
|
|
|
+ 'valid': self.valid,
|
|
|
+ }
|
|
|
|
|
|
# Optional values
|
|
|
if self.arg is not None:
|
|
@@ -227,6 +363,9 @@ class Item3(object):
|
|
|
if self.autocomplete is not None:
|
|
|
o['autocomplete'] = self.autocomplete
|
|
|
|
|
|
+ if self.match is not None:
|
|
|
+ o['match'] = self.match
|
|
|
+
|
|
|
if self.uid is not None:
|
|
|
o['uid'] = self.uid
|
|
|
|
|
@@ -236,6 +375,12 @@ class Item3(object):
|
|
|
if self.quicklookurl is not None:
|
|
|
o['quicklookurl'] = self.quicklookurl
|
|
|
|
|
|
+ if self.variables:
|
|
|
+ o['variables'] = self.variables
|
|
|
+
|
|
|
+ if self.config:
|
|
|
+ o['config'] = self.config
|
|
|
+
|
|
|
# Largetype and copytext
|
|
|
text = self._text()
|
|
|
if text:
|
|
@@ -245,11 +390,6 @@ class Item3(object):
|
|
|
if icon:
|
|
|
o['icon'] = icon
|
|
|
|
|
|
- # Variables and config
|
|
|
- js = self._vars_and_config()
|
|
|
- if js:
|
|
|
- o['arg'] = js
|
|
|
-
|
|
|
# Modifiers
|
|
|
mods = self._modifiers()
|
|
|
if mods:
|
|
@@ -262,6 +402,7 @@ class Item3(object):
|
|
|
|
|
|
Returns:
|
|
|
dict: Mapping for item `icon` (may be empty).
|
|
|
+
|
|
|
"""
|
|
|
icon = {}
|
|
|
if self.icon is not None:
|
|
@@ -277,6 +418,7 @@ class Item3(object):
|
|
|
|
|
|
Returns:
|
|
|
dict: `text` mapping (may be empty)
|
|
|
+
|
|
|
"""
|
|
|
text = {}
|
|
|
if self.largetext is not None:
|
|
@@ -287,32 +429,12 @@ class Item3(object):
|
|
|
|
|
|
return text
|
|
|
|
|
|
- def _vars_and_config(self):
|
|
|
- """Build `arg` including workflow variables and configuration.
|
|
|
-
|
|
|
- Returns:
|
|
|
- str: JSON string value for `arg` (or `None`)
|
|
|
- """
|
|
|
- if self.variables or self.config:
|
|
|
- d = {}
|
|
|
- if self.variables:
|
|
|
- d['variables'] = self.variables
|
|
|
-
|
|
|
- if self.config:
|
|
|
- d['config'] = self.config
|
|
|
-
|
|
|
- if self.arg is not None:
|
|
|
- d['arg'] = self.arg
|
|
|
-
|
|
|
- return json.dumps({'alfredworkflow': d})
|
|
|
-
|
|
|
- return None
|
|
|
-
|
|
|
def _modifiers(self):
|
|
|
"""Build `mods` dictionary for JSON feedback.
|
|
|
|
|
|
Returns:
|
|
|
dict: Modifier mapping or `None`.
|
|
|
+
|
|
|
"""
|
|
|
if self.modifiers:
|
|
|
mods = {}
|
|
@@ -325,11 +447,15 @@ class Item3(object):
|
|
|
|
|
|
|
|
|
class Workflow3(Workflow):
|
|
|
- """Workflow class that generates Alfred 3 feedback.
|
|
|
+ """Workflow class that generates Alfred 3+ feedback.
|
|
|
+
|
|
|
+ It is a subclass of :class:`~workflow.Workflow` and most of its
|
|
|
+ methods are documented there.
|
|
|
|
|
|
Attributes:
|
|
|
item_class (class): Class used to generate feedback items.
|
|
|
variables (dict): Top level workflow variables.
|
|
|
+
|
|
|
"""
|
|
|
|
|
|
item_class = Item3
|
|
@@ -337,27 +463,31 @@ class Workflow3(Workflow):
|
|
|
def __init__(self, **kwargs):
|
|
|
"""Create a new :class:`Workflow3` object.
|
|
|
|
|
|
- See :class:`~workflow.workflow.Workflow` for documentation.
|
|
|
+ See :class:`~workflow.Workflow` for documentation.
|
|
|
+
|
|
|
"""
|
|
|
Workflow.__init__(self, **kwargs)
|
|
|
self.variables = {}
|
|
|
self._rerun = 0
|
|
|
- self._session_id = None
|
|
|
+ # Get session ID from environment if present
|
|
|
+ self._session_id = os.getenv('_WF_SESSION_ID') or None
|
|
|
+ if self._session_id:
|
|
|
+ self.setvar('_WF_SESSION_ID', self._session_id)
|
|
|
|
|
|
@property
|
|
|
def _default_cachedir(self):
|
|
|
- """Alfred 3's default cache directory."""
|
|
|
+ """Alfred 4's default cache directory."""
|
|
|
return os.path.join(
|
|
|
os.path.expanduser(
|
|
|
- '~/Library/Caches/com.runningwithcrayons.Alfred-3/'
|
|
|
+ '~/Library/Caches/com.runningwithcrayons.Alfred/'
|
|
|
'Workflow Data/'),
|
|
|
self.bundleid)
|
|
|
|
|
|
@property
|
|
|
def _default_datadir(self):
|
|
|
- """Alfred 3's default data directory."""
|
|
|
+ """Alfred 4's default data directory."""
|
|
|
return os.path.join(os.path.expanduser(
|
|
|
- '~/Library/Application Support/Alfred 3/Workflow Data/'),
|
|
|
+ '~/Library/Application Support/Alfred/Workflow Data/'),
|
|
|
self.bundleid)
|
|
|
|
|
|
@property
|
|
@@ -386,19 +516,17 @@ class Workflow3(Workflow):
|
|
|
|
|
|
"""
|
|
|
if not self._session_id:
|
|
|
- sid = os.getenv('_WF_SESSION_ID')
|
|
|
- if not sid:
|
|
|
- from uuid import uuid4
|
|
|
- sid = uuid4().hex
|
|
|
- self.setvar('_WF_SESSION_ID', sid)
|
|
|
-
|
|
|
- self._session_id = sid
|
|
|
+ from uuid import uuid4
|
|
|
+ self._session_id = uuid4().hex
|
|
|
+ self.setvar('_WF_SESSION_ID', self._session_id)
|
|
|
|
|
|
return self._session_id
|
|
|
|
|
|
- def setvar(self, name, value):
|
|
|
+ def setvar(self, name, value, persist=False):
|
|
|
"""Set a "global" workflow variable.
|
|
|
|
|
|
+ .. versionchanged:: 1.33
|
|
|
+
|
|
|
These variables are always passed to downstream workflow objects.
|
|
|
|
|
|
If you have set :attr:`rerun`, these variables are also passed
|
|
@@ -407,8 +535,15 @@ class Workflow3(Workflow):
|
|
|
Args:
|
|
|
name (unicode): Name of variable.
|
|
|
value (unicode): Value of variable.
|
|
|
+ persist (bool, optional): Also save variable to ``info.plist``?
|
|
|
+
|
|
|
"""
|
|
|
self.variables[name] = value
|
|
|
+ if persist:
|
|
|
+ from .util import set_config
|
|
|
+ set_config(name, value, self.bundleid)
|
|
|
+ self.logger.debug('saved variable %r with value %r to info.plist',
|
|
|
+ name, value)
|
|
|
|
|
|
def getvar(self, name, default=None):
|
|
|
"""Return value of workflow variable for ``name`` or ``default``.
|
|
@@ -419,16 +554,22 @@ class Workflow3(Workflow):
|
|
|
|
|
|
Returns:
|
|
|
unicode or ``default``: Value of variable if set or ``default``.
|
|
|
+
|
|
|
"""
|
|
|
return self.variables.get(name, default)
|
|
|
|
|
|
def add_item(self, title, subtitle='', arg=None, autocomplete=None,
|
|
|
- valid=False, uid=None, icon=None, icontype=None,
|
|
|
- type=None, largetext=None, copytext=None, quicklookurl=None):
|
|
|
+ valid=False, uid=None, icon=None, icontype=None, type=None,
|
|
|
+ largetext=None, copytext=None, quicklookurl=None, match=None):
|
|
|
"""Add an item to be output to Alfred.
|
|
|
|
|
|
- See :meth:`~workflow.workflow.Workflow.add_item` for the main
|
|
|
- documentation.
|
|
|
+ Args:
|
|
|
+ match (unicode, optional): If you have "Alfred filters results"
|
|
|
+ turned on for your Script Filter, Alfred (version 3.5 and
|
|
|
+ above) will filter against this field, not ``title``.
|
|
|
+
|
|
|
+ See :meth:`Workflow.add_item() <workflow.Workflow.add_item>` for
|
|
|
+ the main documentation and other parameters.
|
|
|
|
|
|
The key difference is that this method does not support the
|
|
|
``modifier_subtitles`` argument. Use the :meth:`~Item3.add_modifier()`
|
|
@@ -436,17 +577,26 @@ class Workflow3(Workflow):
|
|
|
|
|
|
Returns:
|
|
|
Item3: Alfred feedback item.
|
|
|
+
|
|
|
"""
|
|
|
- item = self.item_class(title, subtitle, arg,
|
|
|
- autocomplete, valid, uid, icon, icontype, type,
|
|
|
+ item = self.item_class(title, subtitle, arg, autocomplete,
|
|
|
+ match, valid, uid, icon, icontype, type,
|
|
|
largetext, copytext, quicklookurl)
|
|
|
|
|
|
+ # Add variables to child item
|
|
|
+ item.variables.update(self.variables)
|
|
|
+
|
|
|
self._items.append(item)
|
|
|
return item
|
|
|
|
|
|
+ @property
|
|
|
+ def _session_prefix(self):
|
|
|
+ """Filename prefix for current session."""
|
|
|
+ return '_wfsess-{0}-'.format(self.session_id)
|
|
|
+
|
|
|
def _mk_session_name(self, name):
|
|
|
"""New cache name/key based on session ID."""
|
|
|
- return '_wfsess-{0}-{1}'.format(self.session_id, name)
|
|
|
+ return self._session_prefix + name
|
|
|
|
|
|
def cache_data(self, name, data, session=False):
|
|
|
"""Cache API with session-scoped expiry.
|
|
@@ -459,11 +609,11 @@ class Workflow3(Workflow):
|
|
|
session (bool, optional): Whether to scope the cache
|
|
|
to the current session.
|
|
|
|
|
|
- ``name`` and ``data`` are as for the
|
|
|
- :meth:`~workflow.workflow.Workflow.cache_data` on
|
|
|
- :class:`~workflow.workflow.Workflow`.
|
|
|
+ ``name`` and ``data`` are the same as for the
|
|
|
+ :meth:`~workflow.Workflow.cache_data` method on
|
|
|
+ :class:`~workflow.Workflow`.
|
|
|
|
|
|
- If ``session`` is ``True``, the ``name`` variable is prefixed
|
|
|
+ If ``session`` is ``True``, then ``name`` is prefixed
|
|
|
with :attr:`session_id`.
|
|
|
|
|
|
"""
|
|
@@ -485,11 +635,11 @@ class Workflow3(Workflow):
|
|
|
session (bool, optional): Whether to scope the cache
|
|
|
to the current session.
|
|
|
|
|
|
- ``name``, ``data_func`` and ``max_age`` are as for the
|
|
|
- :meth:`~workflow.workflow.Workflow.cached_data` on
|
|
|
- :class:`~workflow.workflow.Workflow`.
|
|
|
+ ``name``, ``data_func`` and ``max_age`` are the same as for the
|
|
|
+ :meth:`~workflow.Workflow.cached_data` method on
|
|
|
+ :class:`~workflow.Workflow`.
|
|
|
|
|
|
- If ``session`` is ``True``, the ``name`` variable is prefixed
|
|
|
+ If ``session`` is ``True``, then ``name`` is prefixed
|
|
|
with :attr:`session_id`.
|
|
|
|
|
|
"""
|
|
@@ -498,13 +648,25 @@ class Workflow3(Workflow):
|
|
|
|
|
|
return super(Workflow3, self).cached_data(name, data_func, max_age)
|
|
|
|
|
|
- def clear_session_cache(self):
|
|
|
- """Remove *all* session data from the cache.
|
|
|
+ def clear_session_cache(self, current=False):
|
|
|
+ """Remove session data from the cache.
|
|
|
|
|
|
.. versionadded:: 1.25
|
|
|
+ .. versionchanged:: 1.27
|
|
|
+
|
|
|
+ By default, data belonging to the current session won't be
|
|
|
+ deleted. Set ``current=True`` to also clear current session.
|
|
|
+
|
|
|
+ Args:
|
|
|
+ current (bool, optional): If ``True``, also remove data for
|
|
|
+ current session.
|
|
|
+
|
|
|
"""
|
|
|
def _is_session_file(filename):
|
|
|
- return filename.startswith('_wfsess-')
|
|
|
+ if current:
|
|
|
+ return filename.startswith('_wfsess-')
|
|
|
+ return filename.startswith('_wfsess-') \
|
|
|
+ and not filename.startswith(self._session_prefix)
|
|
|
|
|
|
self.clear_cache(_is_session_file)
|
|
|
|
|
@@ -514,6 +676,7 @@ class Workflow3(Workflow):
|
|
|
|
|
|
Returns:
|
|
|
dict: Data suitable for Alfred 3 feedback.
|
|
|
+
|
|
|
"""
|
|
|
items = []
|
|
|
for item in self._items:
|
|
@@ -526,7 +689,36 @@ class Workflow3(Workflow):
|
|
|
o['rerun'] = self.rerun
|
|
|
return o
|
|
|
|
|
|
+ def warn_empty(self, title, subtitle=u'', icon=None):
|
|
|
+ """Add a warning to feedback if there are no items.
|
|
|
+
|
|
|
+ .. versionadded:: 1.31
|
|
|
+
|
|
|
+ Add a "warning" item to Alfred feedback if no other items
|
|
|
+ have been added. This is a handy shortcut to prevent Alfred
|
|
|
+ from showing its fallback searches, which is does if no
|
|
|
+ items are returned.
|
|
|
+
|
|
|
+ Args:
|
|
|
+ title (unicode): Title of feedback item.
|
|
|
+ subtitle (unicode, optional): Subtitle of feedback item.
|
|
|
+ icon (str, optional): Icon for feedback item. If not
|
|
|
+ specified, ``ICON_WARNING`` is used.
|
|
|
+
|
|
|
+ Returns:
|
|
|
+ Item3: Newly-created item.
|
|
|
+
|
|
|
+ """
|
|
|
+ if len(self._items):
|
|
|
+ return
|
|
|
+
|
|
|
+ icon = icon or ICON_WARNING
|
|
|
+ return self.add_item(title, subtitle, icon=icon)
|
|
|
+
|
|
|
def send_feedback(self):
|
|
|
"""Print stored items to console/Alfred as JSON."""
|
|
|
- json.dump(self.obj, sys.stdout)
|
|
|
+ if self.debugging:
|
|
|
+ json.dump(self.obj, sys.stdout, indent=2, separators=(',', ': '))
|
|
|
+ else:
|
|
|
+ json.dump(self.obj, sys.stdout)
|
|
|
sys.stdout.flush()
|