Skip to content
This repository has been archived by the owner on Mar 4, 2018. It is now read-only.

Commit

Permalink
Searchlight release refactoring
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
kopischke committed Apr 9, 2013
1 parent ae8264a commit d14c741
Showing 1 changed file with 81 additions and 55 deletions.
136 changes: 81 additions & 55 deletions src/numbers
@@ -1,73 +1,99 @@
#!/usr/bin/env bash #!/usr/bin/env bash
scriptdir="${0%/*}"
export LC_CTYPE='en_US.UTF-8' # UTF-8 case awareness 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]%/*}" scriptdir="${BASH_SOURCE[0]%/*}"
source "$scriptdir"/lib/strings.sh


# assign arguments # Parse arguments
query=($query) desc=''; icon=''
desc="${2:-main phone number}" case "$1" in
code="${3:-%p}" --found)
icon="${4:-vCard.png}" 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 desc="${desc:-${1#--} phone number}"
ucase='[[:upper:]]' icon="${icon:-vCard.png}"
[[ ${query[0]:0:1} =~ $ucase ]] && shopt -u nocasematch || shopt -s nocasematch


blank='^[[:space:]]*$' if ! is_blank $2; then
if [[ ! "${query[0]}" =~ $blank ]]; then # Normalize Unicode representation of characters with diacritics
# start XML output is_7bit "${*:2}" && query=(${*:2}) || query=($(utf8_normalize "${*:2}"))

# Start XML output
source "$scriptdir"/lib/feedback.sh source "$scriptdir"/lib/feedback.sh
feedback --start feedback --start

# get Contacts data for query # Get contact data matching query
names=(); numbers=(); uids=() prev_title=''; prev_number=''; matches=0
while read -r || [[ -n "$REPLY" ]]; do while read -r || [[ -n "$REPLY" ]]; do
# split names and numbers on UID (as a makeshift record separator) # Catch contacts’ stdout message on 0 matches
# filtering out non-matching names (as contacts itself only accepts a single, [[ $REPLY == 'error: no one found' ]] && break
# 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' # Parse contact output line into record items
has_phone="(.*) ($uid_regex) (.*) $uid_regex (.+)" IFS=$'\t' record=($REPLY)
has_query=".*${query[*]}.*" name="${record[0]#:}"
if [[ $REPLY =~ $has_phone ]]; then uid="${record[1]}"
[[ ${BASH_REMATCH[1]} != ' ' ]] && name="${BASH_REMATCH[1]}" || unset name nick="${record[2]#:}"
uid="${BASH_REMATCH[2]}" [[ ${record[3]#:} != "$name" ]] && company="${record[3]#:}" || company=''
company="${BASH_REMATCH[4]}" number="${record[4]}"
number="${BASH_REMATCH[6]}" title=''
# if we match on name, add company name (if any), and vice versa
if [[ $name =~ $has_query ]]; then names+=("$name${company:+ ($company)}") # Only keep records with a phone number
elif [[ $company =~ $has_query ]]; then names+=("$company${name:+ – $name}") if [[ -n "$number" ]]; then
else continue # skip when no full match is found # Word incremental search; first match defines display format
fi for q in "${query[@]}"; do
numbers+=("$number") # Query words starting with an upper case letter are case sensitive
uids+=("$uid") 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"

# Store control var values
prev_title="$title"; prev_number="$number"; let matches++
fi fi
done < <("$scriptdir"/contacts -SHs -f "%fn %ln %u %c %u $code" ${query[0]}) done < <("$scriptdir"/contacts -SH -f "$code" ${query[0]} | sort)


# create XML items from matching contact items # Create fallback item if no matching records are found
# (check for error message as sends these to stdout) if (( $matches < 1 )); then
if (( ${#names[@]} > 0 )) && [[ ${names[0]} != 'error: no one found' ]]; then title='No matching contacts found'
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"
text="Action this item to run Alfred default searches for “${query[*]}”." text="Action this item to run Alfred default searches for “${query[*]}”."
arg="alfredsearch:${query[*]}" arg="alfredsearch:${query[*]}"
icon='/Applications/Contacts.app' icon='/Applications/Contacts.app'
feedback "$title" --subtitle="$text" --uid='noresults' --action="$arg" --icon="$icon" --fileicon feedback "$title" --subtitle="$text" --uid='noresults' --action="$arg" --icon="$icon" --fileicon
fi fi

# end XML output # End XML output
feedback --end feedback --end
fi fi

0 comments on commit d14c741

Please sign in to comment.