Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
base fork: kopischke/alfred-pushdial
base: 0a6cf5e2fa
...
head fork: kopischke/alfred-pushdial
compare: d69457bdfc
  • 7 commits
  • 8 files changed
  • 0 commit comments
  • 1 contributor
Commits on Apr 09, 2013
@kopischke Factored out common string operations into sourceable library a495b14
@kopischke Added --file option for draggable file items
Also tightened code and cleaned up comments.
db9fc5d
@kopischke Set case comparison to use en_US.UTF-8 locale
Brings UTF-8 case awareness to string operations. Fixes #3
c89fa42
@kopischke Make script dir detection sourcing safe
`$0` is set to `-bash` when sourced. Use `${BASH_SOURCE[0]}` instead.
ae8264a
@kopischke Searchlight release refactoring
Allow for broader range of phone numbers to llok for; define our own
“first found” phone order (excluding fax numbers); include nickname
into searched name fields (fixes #4); refine queries incrementally
against all fields, word by word.
d14c741
@kopischke Use vCard file type icon defined by system
Allows removal of another unused icon file.
6b33101
@kopischke Release 1.1.0
Alleyoop, new style
d69457b
View
BIN  Dial with PushDialer.alfredworkflow
Binary file not shown
View
14 src/info.plist
@@ -238,7 +238,7 @@ print "{query}" if is_alfred_search?</string>
<key>runningsubtext</key>
<string>Searching work phone numbers for “{query}”…</string>
<key>script</key>
- <string>./numbers '{query}' 'work phone number' '%wp'</string>
+ <string>./numbers --work "{query}"</string>
<key>subtext</key>
<string>Find work phone number for “{query}”.</string>
<key>title</key>
@@ -265,7 +265,7 @@ print "{query}" if is_alfred_search?</string>
<key>runningsubtext</key>
<string>Searching home numbers for “{query}”…</string>
<key>script</key>
- <string>./numbers '{query}' 'home phone number' '%hp'</string>
+ <string>./numbers --home "{query}"</string>
<key>subtext</key>
<string>Find main home number for “{query}”.</string>
<key>title</key>
@@ -340,7 +340,7 @@ print "{query}" if is_alfred_search?</string>
<key>runningsubtext</key>
<string>Searching mobile phone numbers for “{query}”…</string>
<key>script</key>
- <string>./numbers '{query}' 'mobile phone number' '%mp'</string>
+ <string>./numbers --mobile "{query}"</string>
<key>subtext</key>
<string>Find mobile phone number for “{query}”.</string>
<key>title</key>
@@ -409,13 +409,13 @@ print sanitize_query unless is_alfred_search?</string>
<key>keyword</key>
<string>call</string>
<key>runningsubtext</key>
- <string>Searching main phone numbers for “{query}”…</string>
+ <string>Searching all phone numbers for “{query}”…</string>
<key>script</key>
- <string>./numbers '{query}'</string>
+ <string>./numbers --found "{query}"</string>
<key>subtext</key>
- <string>Find main phone number for “{query}”</string>
+ <string>Find a phone number for “{query}”</string>
<key>title</key>
- <string>Call a contact’s main phone</string>
+ <string>Call a contact’s first found phone</string>
<key>type</key>
<integer>0</integer>
<key>withspace</key>
View
52 src/lib/feedback.sh
@@ -4,8 +4,11 @@
#
# then, for every item repeat:
#
-# feedback title [--subtitle=subtitle] [--uid=uid] [--action=action] [--valid]
-# [--completion=completion] [--icon=icon] [--fileicon|--filetype]
+# feedback title [--subtitle=subtitle] [--uid=uid]
+# [--action=action] [--valid] [--file]
+# [--completion=completion]
+# [--icon=icon] [--fileicon|--filetype]
+#
# finally, call:
#
# feedback --end
@@ -13,50 +16,47 @@
function feedback {
case "$1" in
--start) # start of XML output
- echo '<?xml version="1.0" encoding="'${2:-UTF-8}'"?>'
- echo '<items>'
- ;;
+ echo '<?xml version="1.0" encoding="'${2:-UTF-8}'"?>'
+ echo '<items>' ;;
--end) # end of XML output
- echo '</items>'
- ;;
+ echo '</items>' ;;
?*) # any other string: item XML output
local title="$1"; shift # item title (mandatory)
local subtitle='' # item subtitle
local uid='default' # item uid attribute; you should really set this one!
local action='' # item arg attribute
local valid='no' # item valid attribute
+ local action_type='' # item type attribute
local completion='' # item autocomplete attribute
local icon='' # item icon path or file type ID
- local icon_type='' # icon type attribute
+ local icon_type='' # item icon type attribute
- while (( $# > 0 )); do
- case "$1" in
- --uid=*|--action=*|--completion=*|--subtitle=*|--icon=*)
+ # Parse arguments
+ while (( $# > 0 )); do
+ case "$1" in
+ --uid=*|--action=*|--subtitle=*|--icon=*)
# parse --arg='values' into variable $arg set to 'values'
argname="${1#--}"; argname="${argname%%=*}"
- eval "$argname='${1#*=}'"
- ;;
+ eval "$argname='${1#*=}'" ;;
+ --completion=*)
+ completion=' autocomplete="'"${1#--}"'"' ;;
--valid)
- valid='yes'
- ;;
+ valid='yes' ;;
+ --file)
+ action_type=' type="'"${1#--}"'"' ;;
--fileicon|--filetype)
- icon_type="${1#--}"
- ;;
+ icon_type=' type="'"${1#--}"'"' ;;
esac
shift
done
- [[ -n "$icon_type" ]] && icon_type=' type="'"$icon_type"'"'
- [[ -n "$completion" ]] && completion=' autocomplete="'"$completion"'"'
-
- # always use CDATA tags for node content
- echo '<item uid="'"$uid"'" arg="'"$action"'" valid="'$valid'"'"$completion"'>'
+
+ # Always use CDATA tags for node content
+ echo '<item uid="'"$uid"'" arg="'"$action"'" valid="'$valid'"'"$action_type$completion"'>'
echo '<title><![CDATA['"$title"']]></title>'
[[ -n "$subtitle" ]] && echo '<subtitle><![CDATA['"$subtitle"']]></subtitle>'
[[ -n "$icon" ]] && echo '<icon'"$icon_type"'><![CDATA['"$icon"']]></icon>'
- echo '</item>'
- ;;
+ echo '</item>' ;;
*)
- return 1;
- ;;
+ return 1 ;;
esac
}
View
50 src/lib/strings.sh
@@ -0,0 +1,50 @@
+function is_in_class {
+ local regex="[^$1]"
+ [[ $2 =~ $regex ]] && return 1 || return 0
+}
+
+function is_7bit {
+ local LC_ALL='C' # avoid printing char collation
+ is_in_class '[:cntrl:][:space:][:print:]' "$1"
+}
+
+function is_blank {
+ is_in_class '[:blank:]' "$1"
+}
+
+function is_upper {
+ is_in_class '[:upper:]' "$1"
+}
+
+function is_lower {
+ is_in_class '[:lower:]' "$1"
+}
+
+function is_mixed {
+ ! is_upper "$1" && ! is_lower "$1"
+}
+
+function is_title {
+ is_upper "${1:0:1}" && is_lower "${1:1}"
+}
+
+function utf8_normalize {
+ echo "$1" | iconv -s -f UTF-8-Mac -t UTF-8
+}
+
+function match {
+ local regex="$1"
+ [[ $2 =~ $regex ]] && echo "${BASH_REMATCH[0]}"
+}
+
+function ltrim {
+ echo "$(match '[^[:space:]].*' "$1")"
+}
+
+function rtrim {
+ echo "$(match '[^[:space:]].*$' "$1")"
+}
+
+function trim {
+ echo "$(match '[^[:space:]](.*[^[:space:]])?' "$1")"
+}
View
138 src/numbers
@@ -1,71 +1,99 @@
#!/usr/bin/env bash
-scriptdir="${0%/*}"
+export LC_CTYPE='en_US.UTF-8' # UTF-8 case awareness
-# normalize Unicode representation of characters with diacritics
-not_ascii='[^ -~]'
-[[ "$1" =~ $not_ascii ]] && query="$(echo "$1" | iconv -s -f 'UTF-8-Mac' -t 'UTF-8')" || query="$1"
+scriptdir="${BASH_SOURCE[0]%/*}"
+source "$scriptdir"/lib/strings.sh
-# assign arguments
-query=($query)
-desc="${2:-main phone number}"
-code="${3:-%p}"
-icon="${4:-vCard.png}"
+# Parse arguments
+desc=''; icon=''
+case "$1" in
+ --found)
+ code=$':%n\t%u\t:%nn\t:%c\t%hp\t%wp\t%mp\t%Mp\t%op\t%pp'
+ desc='first found number' ;;
+ --home)
+ code=$':%n\t%u\t:%nn\t:%c\t%hp' ;;
+ --work)
+ code=$':%n\t%u\t:%nn\t:%c\t%wp' ;;
+ --mobile)
+ code=$':%n\t%u\t:%nn\t:%c\t%mp' ;;
+ --main)
+ code=$':%n\t%u\t:%nn\t:%c\t%Mp' ;;
+ --other)
+ code=$':%n\t%u\t:%nn\t:%c\t%op' ;;
+ --pager)
+ code=$':%n\t%u\t:%nn\t:%c\t%pp'
+ desc='pager number' ;;
+ --fax)
+ code=$':%n\t%u\t:%nn\t:%c\t%fp'
+ desc='fax number' ;;
+ *)
+ exit 1 ;;
+esac
-# Searches beginning with a lower case letter are case insensitive
-ucase='[[:upper:]]'
-[[ ${query[0]:0:1} =~ $ucase ]] && shopt -u nocasematch || shopt -s nocasematch
+desc="${desc:-${1#--} phone number}"
+icon="${icon:-public.vcard}"
-blank='^[[:space:]]*$'
-if [[ ! "${query[0]}" =~ $blank ]]; then
- # start XML output
+if ! is_blank $2; then
+ # Normalize Unicode representation of characters with diacritics
+ is_7bit "${*:2}" && query=(${*:2}) || query=($(utf8_normalize "${*:2}"))
+
+ # Start XML output
source "$scriptdir"/lib/feedback.sh
feedback --start
-
- # get Contacts data for query
- names=(); numbers=(); uids=()
+
+ # Get contact data matching query
+ prev_title=''; prev_number=''; matches=0
while read -r || [[ -n "$REPLY" ]]; do
- # split names and numbers on UID (as a makeshift record separator)
- # filtering out non-matching names (as contacts itself only accepts a single,
- # unquoted word as its query) and results without a phone number.
- uid_regex='[A-Z0-9]{8}(-[A-Z0-9]{4}){3}-[A-Z0-9]{12}:ABPerson'
- has_phone="(.*) ($uid_regex) (.*) $uid_regex (.+)"
- has_query=".*${query[*]}.*"
- if [[ $REPLY =~ $has_phone ]]; then
- [[ ${BASH_REMATCH[1]} != ' ' ]] && name="${BASH_REMATCH[1]}" || unset name
- uid="${BASH_REMATCH[2]}"
- company="${BASH_REMATCH[4]}"
- number="${BASH_REMATCH[6]}"
- # if we match on name, add company name (if any), and vice versa
- if [[ $name =~ $has_query ]]; then names+=("$name${company:+ ($company)}")
- elif [[ $company =~ $has_query ]]; then names+=("$company${name:+ – $name}")
- else continue # skip when no full match is found
- fi
- numbers+=("$number")
- uids+=("$uid")
+ # Catch contacts’ stdout message on 0 matches
+ [[ $REPLY == 'error: no one found' ]] && break
+
+ # Parse contact output line into record items
+ IFS=$'\t' record=($REPLY)
+ name="${record[0]#:}"
+ uid="${record[1]}"
+ nick="${record[2]#:}"
+ [[ ${record[3]#:} != "$name" ]] && company="${record[3]#:}" || company=''
+ number="${record[4]}"
+ title=''
+
+ # Only keep records with a phone number
+ if [[ -n "$number" ]]; then
+ # Word incremental search; first match defines display format
+ for q in "${query[@]}"; do
+ # Query words starting with an upper case letter are case sensitive
+ is_lower "$q" && shopt -s nocasematch || shopt -u nocasematch
+ if [[ $name =~ "$q" ]]; then
+ [[ -z "$title" ]] && title="$name${company:+ ($company)}"
+ elif [[ $nick =~ "$q" ]]; then
+ [[ -z "$title" ]] && title="${nick}${name:+ $name}${company:+ ($company)}"
+ elif [[ $company =~ "$q" ]]; then
+ [[ -z "$title" ]] && title="$company${name:+ – $name}"
+ else # next record
+ continue 2
+ fi
+ done
+
+ # Skip duplicate records
+ [[ $title == "$prev_title" && $number == "$prev_number" ]] && continue
+
+ # Output XML feedback item
+ text="Call $desc: $number"
+ feedback "$title" --subtitle="$text" --uid="$uid" --action="$number" --valid --icon="$icon" --filetype
+
+ # Store control var values
+ prev_title="$title"; prev_number="$number"; let matches++
fi
- done < <("$scriptdir"/contacts -SHs -f "%fn %ln %u %c %u $code" ${query[0]})
-
- # create XML items from matching contact items
- # (check for error message as sends these to stdout)
- if (( ${#names[@]} > 0 )) && [[ ${names[0]} != 'error: no one found' ]]; then
- for (( i=0; i < ${#names[@]}; i++ )); do
- name="${names[$i]}"
- number="${numbers[$i]}"
- uid="${uids[$i]}"
- # deduplicate items
- (( i > 0 )) && [[ $name == "${names[$(($i-1))]}" && $number == "${numbers[$(($i-1))]}" ]] && continue
- # XML output
- text="Dial $desc: $number"
- feedback "$name" --subtitle="$text" --uid="$uid" --action="$number" --valid --icon="$icon"
- done
- else # Create fallback XML item
- title="No matching contacts found"
+ done < <("$scriptdir"/contacts -SH -f "$code" ${query[0]} | sort)
+
+ # Create fallback item if no matching records are found
+ if (( $matches < 1 )); then
+ title='No matching contacts found'
text="Action this item to run Alfred default searches for “${query[*]}”."
arg="alfredsearch:${query[*]}"
icon='/Applications/Contacts.app'
feedback "$title" --subtitle="$text" --uid='noresults' --action="$arg" --icon="$icon" --fileicon
fi
-
- # end XML output
+
+ # End XML output
feedback --end
fi
View
2  src/update.json
@@ -1,4 +1,4 @@
{
- "version": 1.02,
+ "version": 1.1,
"remote_json": "https://github.com/kopischke/alfred-pushdial/raw/master/versions.json"
}
View
BIN  src/vCard.png
Deleted file not rendered
View
6 versions.json
@@ -1,5 +1,5 @@
{
- "version": 1.02,
- "download_uri": "https://github.com/kopischke/alfred-pushdial/raw/master/Dial%20with%20PushDialer.alfredworkflow",
- "description": "Queries with non-ASCII characters now work in call commands."
+ "version": 1.1,
+ "download_url": "https://github.com/kopischke/alfred-pushdial/raw/master/Dial%20with%20PushDialer.alfredworkflow",
+ "description": "Searchlight edition: much better call searches."
}

No commit comments for this range

Something went wrong with that request. Please try again.