diff --git a/Default.png b/Default.png new file mode 100644 index 00000000..89acac3e Binary files /dev/null and b/Default.png differ diff --git a/Default@2x.png b/Default@2x.png new file mode 100644 index 00000000..afcdcf98 Binary files /dev/null and b/Default@2x.png differ diff --git a/OnePassword.xcodeproj/project.pbxproj b/OnePassword.xcodeproj/project.pbxproj index a2caa33b..98a7fee5 100644 --- a/OnePassword.xcodeproj/project.pbxproj +++ b/OnePassword.xcodeproj/project.pbxproj @@ -27,6 +27,8 @@ DA5BFA61147E415C00F98B1E /* MainStoryboard_iPad.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DA5BFA5F147E415C00F98B1E /* MainStoryboard_iPad.storyboard */; }; DA5BFA64147E415C00F98B1E /* OnePassword.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = DA5BFA62147E415C00F98B1E /* OnePassword.xcdatamodeld */; }; DA5BFA67147E415C00F98B1E /* OPMainViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DA5BFA66147E415C00F98B1E /* OPMainViewController.m */; }; + DA5DB7A614BE4B19002DD256 /* Default.png in Resources */ = {isa = PBXBuildFile; fileRef = DA5DB7A514BE4B19002DD256 /* Default.png */; }; + DA5DB7A814BE4B4B002DD256 /* Default@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA5DB7A714BE4B4B002DD256 /* Default@2x.png */; }; DA7C28C414AF078900491972 /* Bold_Lines.png in Resources */ = {isa = PBXBuildFile; fileRef = DA7C28A514AF078900491972 /* Bold_Lines.png */; }; DA7C28C514AF078900491972 /* Box.png in Resources */ = {isa = PBXBuildFile; fileRef = DA7C28A614AF078900491972 /* Box.png */; }; DA7C28C614AF078900491972 /* Dashed_Divider.png in Resources */ = {isa = PBXBuildFile; fileRef = DA7C28A714AF078900491972 /* Dashed_Divider.png */; }; @@ -58,6 +60,12 @@ DA7C28E014AF078900491972 /* Smooth_Divider.png in Resources */ = {isa = PBXBuildFile; fileRef = DA7C28C114AF078900491972 /* Smooth_Divider.png */; }; DA7C28E114AF078900491972 /* Square.png in Resources */ = {isa = PBXBuildFile; fileRef = DA7C28C214AF078900491972 /* Square.png */; }; DA7C28E214AF078900491972 /* White_Rectangular.png in Resources */ = {isa = PBXBuildFile; fileRef = DA7C28C314AF078900491972 /* White_Rectangular.png */; }; + DAAF5C2214BF308400A0F1F0 /* Background.png in Resources */ = {isa = PBXBuildFile; fileRef = DAAF5C2014BF308400A0F1F0 /* Background.png */; }; + DAAF5C2314BF308400A0F1F0 /* Background@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DAAF5C2114BF308400A0F1F0 /* Background@2x.png */; }; + DABF7DA514BE54E4007F3557 /* Default.png in Resources */ = {isa = PBXBuildFile; fileRef = DABF7DA414BE54E4007F3557 /* Default.png */; }; + DABF7DAA14BE561C007F3557 /* Icon-72.png in Resources */ = {isa = PBXBuildFile; fileRef = DABF7DA714BE561C007F3557 /* Icon-72.png */; }; + DABF7DAB14BE561C007F3557 /* Icon.png in Resources */ = {isa = PBXBuildFile; fileRef = DABF7DA814BE561C007F3557 /* Icon.png */; }; + DABF7DAC14BE561C007F3557 /* Icon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABF7DA914BE561C007F3557 /* Icon@2x.png */; }; DAC6325E1486805C0075AEA5 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4A147E415C00F98B1E /* Foundation.framework */; }; DAC6326D148680650075AEA5 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4A147E415C00F98B1E /* Foundation.framework */; }; DAC63277148680700075AEA5 /* libuicolor-utilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC6325D1486805C0075AEA5 /* libuicolor-utilities.a */; }; @@ -195,6 +203,8 @@ DA5BFA63147E415C00F98B1E /* OnePassword.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = OnePassword.xcdatamodel; sourceTree = ""; }; DA5BFA65147E415C00F98B1E /* OPMainViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OPMainViewController.h; sourceTree = ""; }; DA5BFA66147E415C00F98B1E /* OPMainViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OPMainViewController.m; sourceTree = ""; }; + DA5DB7A514BE4B19002DD256 /* Default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Default.png; path = ../Default.png; sourceTree = ""; }; + DA5DB7A714BE4B4B002DD256 /* Default@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Default@2x.png"; path = "../Default@2x.png"; sourceTree = ""; }; DA7C28A514AF078900491972 /* Bold_Lines.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Bold_Lines.png; sourceTree = ""; }; DA7C28A614AF078900491972 /* Box.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Box.png; sourceTree = ""; }; DA7C28A714AF078900491972 /* Dashed_Divider.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Dashed_Divider.png; sourceTree = ""; }; @@ -226,6 +236,12 @@ DA7C28C114AF078900491972 /* Smooth_Divider.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Smooth_Divider.png; sourceTree = ""; }; DA7C28C214AF078900491972 /* Square.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Square.png; sourceTree = ""; }; DA7C28C314AF078900491972 /* White_Rectangular.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = White_Rectangular.png; sourceTree = ""; }; + DAAF5C2014BF308400A0F1F0 /* Background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Background.png; sourceTree = ""; }; + DAAF5C2114BF308400A0F1F0 /* Background@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Background@2x.png"; sourceTree = ""; }; + DABF7DA414BE54E4007F3557 /* Default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Default.png; sourceTree = SOURCE_ROOT; }; + DABF7DA714BE561C007F3557 /* Icon-72.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-72.png"; sourceTree = ""; }; + DABF7DA814BE561C007F3557 /* Icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Icon.png; sourceTree = ""; }; + DABF7DA914BE561C007F3557 /* Icon@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon@2x.png"; sourceTree = ""; }; DAC6325D1486805C0075AEA5 /* libuicolor-utilities.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libuicolor-utilities.a"; sourceTree = BUILT_PRODUCTS_DIR; }; DAC6326C148680650075AEA5 /* libjrswizzle.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libjrswizzle.a; sourceTree = BUILT_PRODUCTS_DIR; }; DAC632791486809A0075AEA5 /* JRSwizzle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JRSwizzle.h; path = External/Pearl/External/jrswizzle/JRSwizzle.h; sourceTree = SOURCE_ROOT; }; @@ -1421,6 +1437,13 @@ DA5BFA51147E415C00F98B1E /* Supporting Files */ = { isa = PBXGroup; children = ( + DAAF5C2014BF308400A0F1F0 /* Background.png */, + DAAF5C2114BF308400A0F1F0 /* Background@2x.png */, + DABF7DA714BE561C007F3557 /* Icon-72.png */, + DABF7DA814BE561C007F3557 /* Icon.png */, + DABF7DA914BE561C007F3557 /* Icon@2x.png */, + DA5DB7A714BE4B4B002DD256 /* Default@2x.png */, + DA5DB7A514BE4B19002DD256 /* Default.png */, DA7C28A414AF078900491972 /* divider */, DA5BFA52147E415C00F98B1E /* OnePassword-Info.plist */, DA5BFA53147E415C00F98B1E /* InfoPlist.strings */, @@ -1569,6 +1592,7 @@ DAC77CD31482AAD600BCF976 /* Resources */ = { isa = PBXGroup; children = ( + DABF7DA414BE54E4007F3557 /* Default.png */, DAC77CD41482AAD600BCF976 /* Pearl.strings */, ); path = Resources; @@ -2861,6 +2885,14 @@ DA7C28E214AF078900491972 /* White_Rectangular.png in Resources */, DA007F5514B25EE100251337 /* ciphers.plist in Resources */, DA007F5614B26EFA00251337 /* Pearl.strings in Resources */, + DA5DB7A614BE4B19002DD256 /* Default.png in Resources */, + DA5DB7A814BE4B4B002DD256 /* Default@2x.png in Resources */, + DABF7DA514BE54E4007F3557 /* Default.png in Resources */, + DABF7DAA14BE561C007F3557 /* Icon-72.png in Resources */, + DABF7DAB14BE561C007F3557 /* Icon.png in Resources */, + DABF7DAC14BE561C007F3557 /* Icon@2x.png in Resources */, + DAAF5C2214BF308400A0F1F0 /* Background.png in Resources */, + DAAF5C2314BF308400A0F1F0 /* Background@2x.png in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/OnePassword/Background.png b/OnePassword/Background.png new file mode 100644 index 00000000..30f3dd65 Binary files /dev/null and b/OnePassword/Background.png differ diff --git a/OnePassword/Background@2x.png b/OnePassword/Background@2x.png new file mode 100644 index 00000000..655b7836 Binary files /dev/null and b/OnePassword/Background@2x.png differ diff --git a/OnePassword/Icon-72.png b/OnePassword/Icon-72.png new file mode 100644 index 00000000..b49a6ebd Binary files /dev/null and b/OnePassword/Icon-72.png differ diff --git a/OnePassword/Icon-Small-50.png b/OnePassword/Icon-Small-50.png new file mode 100644 index 00000000..b59446c0 Binary files /dev/null and b/OnePassword/Icon-Small-50.png differ diff --git a/OnePassword/Icon-Small.png b/OnePassword/Icon-Small.png new file mode 100644 index 00000000..80e85d29 Binary files /dev/null and b/OnePassword/Icon-Small.png differ diff --git a/OnePassword/Icon-Small@2x.png b/OnePassword/Icon-Small@2x.png new file mode 100644 index 00000000..08a1e8a3 Binary files /dev/null and b/OnePassword/Icon-Small@2x.png differ diff --git a/OnePassword/Icon.png b/OnePassword/Icon.png new file mode 100644 index 00000000..9e766d28 Binary files /dev/null and b/OnePassword/Icon.png differ diff --git a/OnePassword/Icon@2x.png b/OnePassword/Icon@2x.png new file mode 100644 index 00000000..874aaca1 Binary files /dev/null and b/OnePassword/Icon@2x.png differ diff --git a/OnePassword/OPMainViewController.h b/OnePassword/OPMainViewController.h index eec06956..e171f94b 100644 --- a/OnePassword/OPMainViewController.h +++ b/OnePassword/OPMainViewController.h @@ -20,5 +20,6 @@ @property (weak, nonatomic) IBOutlet UISegmentedControl *contentType; - (IBAction)didChangeContentType:(UISegmentedControl *)sender; +- (IBAction)didTriggerContent:(id)sender; @end diff --git a/OnePassword/OPMainViewController.m b/OnePassword/OPMainViewController.m index 42464420..ea5041b8 100644 --- a/OnePassword/OPMainViewController.m +++ b/OnePassword/OPMainViewController.m @@ -55,6 +55,7 @@ // Because IB's edit button doesn't auto-toggle self.editable like editButtonItem does. self.navigationItem.rightBarButtonItem = self.editButtonItem; + self.tableView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"Background.png"]]; [super viewDidLoad]; } @@ -91,7 +92,9 @@ - (void)updateWasAnimated:(BOOL)animated { - self.typeLabel.text = self.activeElement? NSStringFromOPElementType(self.activeElement.type): @"moo"; + self.searchDisplayController.searchBar.placeholder = self.activeElement.name; + + self.typeLabel.text = self.activeElement? NSStringFromOPElementType(self.activeElement.type): @""; self.contentTextView.alpha = self.contentType.selectedSegmentIndex == OPElementContentTypeNote? 1: 0; self.contentTextView.editable = self.editing && self.activeElement.type & OPElementTypeStored; @@ -106,9 +109,6 @@ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{ NSString *contentDescription = self.activeElement.contentDescription; - if (contentDescription) - [self.activeElement use]; - dispatch_async(dispatch_get_main_queue(), ^{ self.contentField.text = contentDescription; }); @@ -123,6 +123,12 @@ [self updateAnimated:YES]; } +- (IBAction)didTriggerContent:(id)sender { + + [[UIPasteboard generalPasteboard] setValue:self.activeElement.content + forPasteboardType:self.activeElement.contentUTI]; +} + - (void)didSelectType:(OPElementType)type { self.activeElement.type = type; @@ -132,10 +138,11 @@ - (void)didSelectElement:(OPElementEntity *)element { self.activeElement = element; + [self.activeElement use]; [self updateAnimated:YES]; + self.searchDisplayController.searchBar.text = @""; [self.searchDisplayController setActive:NO animated:YES]; - self.searchDisplayController.searchBar.text = self.activeElement.name; } - (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar { @@ -143,4 +150,9 @@ [self updateAnimated:YES]; } +- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath { + + return NO; +} + @end diff --git a/OnePassword/OnePassword-Info.plist b/OnePassword/OnePassword-Info.plist index 4271177b..ec2bd3b5 100644 --- a/OnePassword/OnePassword-Info.plist +++ b/OnePassword/OnePassword-Info.plist @@ -9,7 +9,25 @@ CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIconFiles - + + Icon.png + Icon@2x.png + Icon-72.png + + CFBundleIcons + + CFBundlePrimaryIcon + + CFBundleIconFiles + + Icon.png + Icon@2x.png + Icon-72.png + + UIPrerenderedIcon + + + CFBundleIdentifier com.lyndir.lhunath.${PRODUCT_NAME:rfc1034identifier} CFBundleInfoDictionaryVersion @@ -32,12 +50,12 @@ MainStoryboard_iPhone UIMainStoryboardFile~ipad MainStoryboard_iPad + UIPrerenderedIcon + UIRequiredDeviceCapabilities armv7 - UIStatusBarStyle - UIStatusBarStyleBlackOpaque UISupportedInterfaceOrientations UIInterfaceOrientationPortrait diff --git a/OnePassword/en.lproj/MainStoryboard_iPhone.storyboard b/OnePassword/en.lproj/MainStoryboard_iPhone.storyboard index 1414a889..1d57fdc5 100644 --- a/OnePassword/en.lproj/MainStoryboard_iPhone.storyboard +++ b/OnePassword/en.lproj/MainStoryboard_iPhone.storyboard @@ -218,15 +218,6 @@ - - - - - - - - - @@ -252,6 +243,9 @@ + + + @@ -269,7 +263,7 @@ - + @@ -292,7 +286,7 @@ - + @@ -352,6 +346,15 @@ + + + + + + + + + @@ -389,6 +392,7 @@ + @@ -408,7 +412,7 @@ - + diff --git a/OnePassword/iTunesArtwork.png b/OnePassword/iTunesArtwork.png new file mode 100644 index 00000000..bbbb32d4 Binary files /dev/null and b/OnePassword/iTunesArtwork.png differ diff --git a/Scripts/bashlib b/Scripts/bashlib new file mode 100644 index 00000000..0e1686b1 --- /dev/null +++ b/Scripts/bashlib @@ -0,0 +1,1168 @@ +#! /usr/bin/env bash +# ___________________________________________________________________________ # +# # +# BashLIB -- A library for Bash scripting convenience. # +# # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); # +# you may not use this file except in compliance with the License. # +# You may obtain a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +# ___________________________________________________________________________ # +# # +# # +# Copyright 2007-2010, lhunath # +# * http://www.lhunath.com # +# * Maarten Billemont # +# # + + + +# ______________________________________________________________________ +# | | +# | .:: GLOBAL CONFIGURATION ::. | +# |______________________________________________________________________| + +{ +shopt -s extglob +shopt -s globstar +} 2>/dev/null ||: + +# Unset all exported functions. Exported functions are evil. +while read _ _ func; do + unset -f "$func" +done < <(declare -Fx) + + + + +# ______________________________________________________________________ +# | | +# | .:: GLOBAL DECLARATIONS ::. | +# |______________________________________________________________________| + +# Variables for global internal operation. +bobber=( '.' 'o' 'O' 'o' ) +spinner=( '-' \\ '|' '/' ) +crosser=( '+' 'x' '+' 'x' ) +runner=( '> >' \ + '>> ' \ + '>>>' \ + ' >>' ) + +# Variables for terminal requests. +[[ -t 1 ]] && { + hide=$( tput civis || tput vi ) + show=$( tput cvvis || tput vs ) + save=$( tput sc ) + load=$( tput rc ) + bold=$( tput bold || tput md ) + reset=$( tput sgr0 || tput me ) + #blink=$( tput blink || tput mb ) + italic=$( tput sitm || tput ZH ) +[[ $TERM != *-m ]] && { + red=$( tput setaf 1|| tput AF 1 ) + green=$( tput setaf 2|| tput AF 2 ) + yellow=$( tput setaf 3|| tput AF 3 ) + blue=$( tput setaf 4|| tput AF 4 ) + magenta=$( tput setaf 5|| tput AF 5 ) + cyan=$( tput setaf 6|| tput AF 6 ) +} + white=$( tput setaf 7|| tput AF 7 ) + default=$( tput op ) + eed=$( tput ed || tput cd ) # Erase to end of display + eel=$( tput el || tput ce ) # Erase to end of line + ebl=$( tput el1 || tput cb ) # Erase to beginning of line + ewl=$eel$ebl # Erase whole line + draw=$( tput -S <<< ' enacs + smacs + acsc + rmacs' || { \ + tput eA; tput as; + tput ac; tput ae; } ) # Drawing characters + back=$'\b' +} 2>/dev/null ||: + + + + + +# ______________________________________________________________________ +# | | +# | .:: FUNCTION DECLARATIONS ::. | +# |______________________________________________________________________| + + + +# ______________________________________________________________________ +# |__ Chr _______________________________________________________________| +# +# chr decimal +# +# Outputs the character that has the given decimal ASCII value. +# +chr() { + printf \\"$(printf '%03o' "$1")" +} # _____________________________________________________________________ + + + +# ______________________________________________________________________ +# |__ Ord _______________________________________________________________| +# +# ord character +# +# Outputs the decimal ASCII value of the given character. +# +ord() { + printf %d "'$1" +} # _____________________________________________________________________ + + + +# ______________________________________________________________________ +# |__ Hex _______________________________________________________________| +# +# hex character +# +# Outputs the hexadecimal ASCII value of the given character. +# +hex() { + printf '%x' "'$1" +} # _____________________________________________________________________ + + + +# ______________________________________________________________________ +# |__ Unhex _______________________________________________________________| +# +# unhex character +# +# Outputs the character that has the given decimal ASCII value. +# +unhex() { + printf \\x"$1" +} # _____________________________________________________________________ + + + +# ______________________________________________________________________ +# |__ Exists ____________________________________________________________| +# +# exists application +# +# Returns successfully if the application is in PATH and is executable +# by the current user. +# +exists() { + [[ -x $(type -P "$1" 2>/dev/null) ]] +} # _____________________________________________________________________ + + + +# ______________________________________________________________________ +# |__ Eol _______________________________________________________________| +# +# eol message +# +# Return termination punctuation for a message, if necessary. +# +eol() { + : #[[ $1 && $1 != *[\!\?.,:\;\|] ]] && printf .. ||: +} # _____________________________________________________________________ + + + +# ______________________________________________________________________ +# |__ CLoc ______________________________________________________________| +# +# cloc +# +# Outputs the current cursor location as two space-separated numbers: row column +# +cloc() { + local old=$(stty -g) + stty raw + + # If the tty has input waiting then we can't read back its response. We'd only break and pollute the tty input buffer. + read -t 0 < /dev/tty 2>/dev/null && { + stty "$old" + return 1 + } + + printf '\e[6n' > /dev/tty + IFS='[;' read -dR _ row col < /dev/tty + printf '%d %d' "$row" "$col" + stty "$old" +} # _____________________________________________________________________ + + + +# ______________________________________________________________________ +# |__ Latest ____________________________________________________________| +# +# latest [file...] +# +# Output the argument that represents the file with the latest modification time. +# +latest() ( + shopt -s nullglob + local file latest=$1 + for file; do + [[ $file -nt $latest ]] && latest=$file + done + printf '%s\n' "$latest" +) + + +# ______________________________________________________________________ +# |__ Emit ______________________________________________________________| +# +# emit [options] message... [-- [command args...]] +# +# Display a message with contextual coloring. +# +# When a command is provided, a spinner will be activated in front of the +# message for as long as the command runs. When the command ends, its +# exit status will result in a message 'done' or 'failed' to be displayed. +# +# It is possible to only specify -- as final argument. This will prepare +# a spinner for you with the given message but leave it up to you to +# notify the spinner that it needs to stop. See the documentation for +# 'spinner' to learn how to do this. +# +# -n Do not end the line with a newline. +# -b Activate bright (bold) mode. +# -d Activate half-bright (dim) mode. +# -g Display in green. +# -y Display in yellow. +# -r Display in red. +# -w Display in the default color. +# +# -[code] A proxy-call to 'spinner -[code]'. +# +# Non-captialized versions of these options affect the * or the spinner +# in front of the message. Capitalized options affect the message text +# displayed. +# +emit() { + + # Proxy call to spinner. + [[ $# -eq 1 && $1 = -+([0-9]) ]] \ + && { spinner $1; return; } + + # Initialize the vars. + local arg + local style= + local color= + local textstyle= + local textcolor= + local noeol=0 + local cmd=0 + + # Parse the options. + spinArgs=() + for arg in $(getArgs odbwgyrDBWGYRn "$@"); do + case ${arg%% } in + d) style=$dim ;; + b) style=$bold ;; + w) color=$white ;; + g) color=$green ;; + y) color=$yellow ;; + r) color=$red ;; + D) textstyle=$dim ;; + B) textstyle=$bold ;; + W) textcolor=$white ;; + G) textcolor=$green ;; + Y) textcolor=$yellow ;; + R) textcolor=$red ;; + n) noeol=1 + spinArgs+=(-n) ;; + o) spinArgs+=("-$arg") ;; + esac + done + shift $(getArgs -c odbwgyrDBWGYRn "$@") + while [[ $1 = +* ]]; do + spinArgs+=("-${1#+}") + shift + done + + # Defaults. + color=${color:-$textcolor} + color=${color:-$green} + [[ $color = $textcolor && -z $style ]] && style=$bold + + # Get the text message. + local text= origtext= + for arg; do [[ $arg = -- ]] && break; origtext+="$arg "; done + origtext=${origtext%% } + (( noeol )) && text=$origtext || text=$origtext$reset$(eol "$origtext")$'\n' + + + # Trim off everything up to -- + while [[ $# -gt 1 && $1 != -- ]]; do shift; done + [[ $1 = -- ]] && { shift; cmd=1; } + + # Figure out what FD to use for our messages. + [[ -t 1 ]]; local fd=$(( $? + 1 )) + + # Display the message or spinner. + if (( cmd )); then + # Don't let this Bash handle SIGINT. + #trap : INT + + # Create the spinner in the background. + spinPipe=${TMPDIR:-/tmp}/bashlib.$$ + { touch "$spinPipe" && rm -f "$spinPipe" && mkfifo "$spinPipe"; } 2>/dev/null \ + || unset spinPipe + { spinner "${spinArgs[@]}" "$origtext" -- "$style" "$color" "$textstyle" "$textcolor" < "${spinPipe:-/dev/null}" & } 2>/dev/null + [[ $spinPipe ]] && echo > "$spinPipe" + spinPid=$! + + # Execute the command for the spinner if one is given. + #sleep 1 # Let the spinner initialize itself properly first. # Can probably remove this now that we echo > spinPipe? + if (( $# == 1 )); then command=$1 + elif (( $# > 1 )); then command=$(printf '%q ' "$@") + else return 0; fi + + eval "$command" >/dev/null \ + && spinner -0 \ + || spinner -1 + else + # Make reset codes restore the initial font. + local font=$reset$textstyle$textcolor + text=$font${text//$reset/$font} + + printf "\r$reset $style$color* %s$reset" "$text" >&$fd + fi +} # _____________________________________________________________________ + + + +# ______________________________________________________________________ +# |__ Spinner ___________________________________________________________| +# +# spinner message... [-- style color textstyle textcolor] +# or +# spinner -[code] +# +# Displays a spinner on the screen that waits until a certain time. +# Best used through its interface provided by 'emit'. +# +# style A terminal control string that defines the style of the spinner. +# color A terminal control string that defines the color of the spinner. +# textstyle A terminal control string that defines the style of the message. +# textcolor A terminal control string that defines the color of the message. +# +# -[code] Shut down a previously activated spinner with the given exit +# code. If the exit code is 0, a green message 'done' will be +# displayed. Otherwise a red message 'failed' will appear. +# The function will return with this exit code as result. +# +# You can manually specify a previously started spinner by putting its PID in +# the 'spinPid' variable. If this variable is not defined, the PID of the most +# recently backgrounded process is used. The 'spinPid' variable is unset upon +# each call to 'spinner' and reset to the PID of the spinner if one is created. +# +spinner() { + + # Check usage. + (( ! $# )) || getArgs -q :h "$@" && { + emit -y 'Please specify a message as argument or a status option.' + return 1 + } + + # Initialize spinner vars. + # Make sure monitor mode is off or we won't be able to trap INT properly. + local monitor=0; [[ $- = *m* ]] && monitor=1 + local done= + + # Place the trap for interrupt signals. + trap 'done="${red}failed"' USR2 + trap 'done="${green}done"' USR1 + + # Initialize the vars. + local pid=${spinPid:-$!} + local graphics=( "${bobber[@]}" ) + local style=$bold + local color=$green + local textstyle= + local textcolor= + local output= + local noeol= + unset spinPid + + # Any remaining options are the exit status of an existing spinner or spinner type. + while [[ $1 = -* ]]; do + arg=${1#-} + shift + + # Stop parsing when arg is -- + [[ $arg = - ]] && break + + # Process arg: Either a spinner type or result code. + if [[ $arg = *[^0-9]* ]]; then + case $arg in + b) graphics=( "${bobber[@]}" ) ;; + c) graphics=( "${crosser[@]}" ) ;; + r) graphics=( "${runner[@]}" ) ;; + s) graphics=( "${spinner[@]}" ) ;; + o) output=1 ;; + n) noeol=1 ;; + esac + elif [[ $pid ]]; then + [[ $arg = 0 ]] \ + && kill -USR1 $pid 2>/dev/null \ + || kill -USR2 $pid 2>/dev/null + + trap - INT + wait $pid 2>/dev/null + + return $arg + fi + done + + # Read arguments. + local text= origtext= + for arg; do [[ $arg = -- ]] && break; origtext+="$arg "; done + origtext=${origtext% } + local styles=$*; [[ $styles = *' -- '* ]] || styles= + read -a styles <<< "${styles##* -- }" + [[ ${styles[0]} ]] && style=${styles[0]} + [[ ${styles[1]} ]] && color=${styles[1]} + [[ ${styles[2]} ]] && textstyle=${styles[2]} + [[ ${styles[3]} ]] && textcolor=${styles[3]} + + # Figure out what FD to use for our messages. + [[ -t 1 ]]; local fd=$(( $? + 1 )) + + # Make reset codes restore the initial font. + local font=$reset$textstyle$textcolor + origtext=$font${origtext//$reset/$font} + (( noeol )) && text=$origtext || text=$origtext$reset$(eol "$origtext") + + # Spinner initial status. + printf "\r$save$eel$reset $style$color* %s$reset" "$text" >&$fd + (( output )) && printf "\n" >&$fd + + # Render the spinner. + set +m + local i=0 + while [[ ! $done ]]; do + IFS= read -r -d '' newtext || true + newtext=${newtext%%$'\n'}; newtext=${newtext##*$'\n'} + if [[ $newtext = +* ]]; then + newtext="$origtext [${newtext#+}]" + fi + if [[ $newtext ]]; then + newtext="$font${newtext//$reset/$font}" + (( noeol )) && text=$newtext || text=$newtext$reset$(eol "$newtext") + fi + + if (( output )) + then printf "\r" >&$fd + else printf "$load$eel" >&$fd + fi + + if (( output )) + then printf "$reset $style$color$blue%s %s$reset" \ + "${graphics[i++ % 4]}" "$text" >&$fd + else printf "$reset $style$color%s %s$reset" \ + "${graphics[i++ % 4]}" "$text" >&$fd + fi + + sleep .25 # Four iterations make one second. + + # Cancel when calling script disappears. + kill -0 $$ >/dev/null || done="${red}aborted" + done + + # Get rid of the spinner traps. + trap - USR1 USR2; (( monitor )) && set -m + + # Spinner final status. + if (( output )) + then text=; printf "\r" >&$fd + else printf "$load" >&$fd + fi + + printf "$eel$reset $style$color* %s${text:+ }$bold%s$font.$reset\n" \ + "$text" "$done" >&$fd +} # _____________________________________________________________________ + + + +# ______________________________________________________________________ +# |__ report ___________________________________________________________| +# +# report [-code] [-e] failure-message [success-message] +# +# This is a convenience function for replacement of spinner -code. +# +# It checks either the exit code of the previously completed command or +# the code provided as option to determine whether to display the success +# or failure message. It calls spinner -code to complete an actively +# emitted message if there is one. The success message is optional. +# +# -[code] The exit code to use. +# -e Exit the script on failure. +# +report() { + + # Exit Status of previous command. + local code=$? + + # Parse the options. + while [[ $1 = -* && $2 ]]; do + arg=${1#-} + shift + + # Stop parsing when arg is -- + [[ $arg = - ]] && break + + # Process arg: Either a spinner type or result code. + if [[ $arg = *[^0-9]* ]]; then + case $arg in + esac + else code=$arg + fi + done + + # Initialize the vars. + local failure=$1 + local success=$2 + + # Check usage. + (( ! $# )) || getArgs -q :h "$@" && { + emit -y 'Please specify at least a failure message as argument.' + return 1 + } + + # Proxy call to spinner. + (( spinPid )) \ + && { spinner -$code; } + + # Success or failure message. + if (( ! code )) + then [[ $success ]] && emit " $success" + else [[ $failure ]] && emit -R " $failure" + fi + + # Pass on exit code. + return $code +} # _____________________________________________________________________ + + + +# ______________________________________________________________________ +# |__ Ask _______________________________________________________________| +# +# ask [-optionchars|+default] message... +# +# Ask a question and read the user's reply to it. +# +# By default, a reply is terminated by a newline. +# +# You may use the options to switch into key mode. In key mode, only a +# single character is read. The valid characters are specified in the +# optionchars. A capital option character makes that option the default. +# +# If the reply character in key mode was not amoungst the provided options +# the default is assumed instead. If no default was given, an exit code +# of 2 is returned. +# +# You may mark an optionchar as 'valid' by appending a '!' to it. As a +# result, an exit code of 0 will only be returned if this valid option +# is replied. If not, an exit code of 1 will be returned. +# +# If no option is marked as valid, the given reply is echoed and an exit +# code of 0 is returned. +# +# You can specify the -# option to make ask hide the user's input. +# +# If you prefix the first argument with a + instead of a -, the remaining +# argument is taken as the default string value and returned when no input +# was received. In this case, the exit code is 0 either way. +# +ask() { + + # Check usage. + (( ! $# )) || getArgs -q :h "$@" && { + emit -y 'Please specify a question as argument.' + return 1 + } + + # Initialize the vars. + local arg + local option= + local options= + local default= + local silent= + local valid= + local muteChar= + + # Parse the options. + if [[ $1 = +* ]]; then + option=${1#+} + default=$option + + shift + else + for arg in $(getArgs "$(printf "%s" {a..z} {A..Z})!#%" "$@"); do + [[ $arg = [[:upper:]] ]] \ + && default=$arg + [[ $arg = ! ]] \ + && { valid=${options: -1}; continue; } + [[ $arg = '#' ]] \ + && { silent=1 arg=; } + [[ $arg = '%' ]] \ + && { silent=1 muteChar='*' arg=; } + + options+=$arg + done + fi + + # Trim off the options. + while [[ $1 = -* ]]; do shift; done + + # Figure out what FD to use for our messages. + [[ -t 1 ]]; local fd=$(( $? + 1 )) + + # Ask the question. + emit -yn "$*${option:+ [$option]}${options:+ [$options]} " + + # Read the reply. + if [[ $muteChar ]]; then + local reply + while read -s -n1 && [[ $REPLY ]]; do + reply+=$REPLY + printf "%s" "$muteChar" >&$fd + done + REPLY=$reply + else + read ${options:+-n1} ${silent:+-s} + fi + [[ $options && $REPLY ]] || (( silent )) && printf "\n" >&$fd + + # Evaluate the reply. + while true; do + if [[ $REPLY && ( ! $options || $options = *$REPLY* ) ]]; then + if [[ $valid ]] + then [[ $REPLY = $valid ]] + else printf "%s" "$REPLY" + fi + + return + fi + + [[ -z $default || $REPLY = $default ]] \ + && return 2 + + REPLY=$default + done +} # _____________________________________________________________________ + + + +# ______________________________________________________________________ +# |__ Trim ______________________________________________________________| +# +# trim lines ... +# +# Trim the whitespace off of the beginning and end of the given lines. +# Each argument is considdered one line; is treated and printed out. +# +# When no arguments are given, lines will be read from standard input. +# +trim() { + + # Initialize the vars. + local lines + local line + local oIFS + + # Get the lines. + lines=( "$@" ) + if (( ! ${#lines[@]} )); then + oIFS=$IFS; IFS=$'\n' + lines=( $(cat) ) + IFS=$oIFS + fi + + # Trim the lines + for line in "${lines[@]}"; do + line=${line##*([[:space:]])}; line=${line%%*([[:space:]])} + printf "%s" "$line" + done +} # _____________________________________________________________________ + + + +# ______________________________________________________________________ +# |__ Reverse ___________________________________________________________| +# +# reverse [-0] [elements ...] [<<< elements] +# +# Reverse the order of the given elements. Elements are read from command +# arguments or standard input if no element arguments are given. +# They are reversed and output on standard output. +# +# If the -0 option is given, input and output are delimited by NUL bytes. +# Otherwise, they are delimited by newlines. +# +reverse() { + + # Initialize the vars. + local elements delimitor=$'\n' + + # Parse the options. + while [[ $1 = -* ]]; do + case $1 in + -0) delimitor=$'\0' ;; + --) shift; break ;; + esac + shift + done + + # Get the elements. + elements=( "$@" ) + if (( ! ${#elements[@]} )); then + while IFS= read -r -d "$delimitor"; do + elements+=("$REPLY") + done + fi + + # Iterate in reverse order. + for (( i=${#elements[@]} - 1; i >=0; --i )); do + printf '%s%s' "${elements[i]}" "$delimitor" + done +} # _____________________________________________________________________ + + + +# ______________________________________________________________________ +# |__ SWait _____________________________________________________________| +# +# swait pid... +# +# Wait for the given PID(s). The PID does not need to be a child of the +# running shell. Note that relying on PIDs always introduces race conditions +# which may be potentially harmful and sometimes even a security issue. +# +# This implementation requires the necessary permissions to send signals +# to the PID(s) provided. +# +swait() { + + # Check usage. + (( ! $# )) || getArgs -q :h "$@" && { + emit -y 'Please provide one or more PIDs to wait for as argument.' + return 1 + } + + # Time to wait. + local pid + for pid; do + while kill -0 $pid 2>/dev/null + do sleep .1; done + done +} # _____________________________________________________________________ + + + +# ______________________________________________________________________ +# |__ GetArgs ___________________________________________________________| +# +# getArgs [options] optstring [args...] +# +# Retrieve all options present in the given arguments. +# +# This is a wrapper for getopts(P) which will safely work inside functions. +# It manages OPTIND for you and returns a list of options found in the +# provided arguments. +# +# optstring This is a string of characters in which each character +# represents an option to look for in the arguments. +# See getopts(P) for a description of the optstring syntax. +# +# args This is a list of arguments in which to look for options. +# Most commonly, you will use "$@" to supply these arguments. +# +# -c Instead of output the arguments, output OPTARGS. +# -q Be quiet. No arguments are displayed. Only the exit code is set. +# -n Use newlines as a separator between the options that were found. +# -0 Use NULL-bytes as a separator between the options that were found. +# +# If any given arguments are found, an exit code of 0 is returned. If none +# are found, an exit code of 1 is returned. +# +# After the operation, OPTARGS is set the the index of the last argument +# that has been parsed by getArgs. Ready for you to use shift $OPTARGS. +# +getArgs() { + + # Check usage. + (( ! $# )) && { + emit -y 'Please provide the arguments to search for in' \ + 'getopts(P) format followed by the positional parameters.' + return 1 + } + + # Initialize the defaults. + local arg + local found=0 + local quiet=0 + local count=0 + local delimitor=' ' + + # Parse the options. + while [[ $1 = -* ]]; do + case $1 in + -q) quiet=1 ;; + -c) count=1 ;; + -n) delimitor=$'\n' ;; + -0) delimitor=$'\0' ;; + esac + shift + done + + # Get the optstring. + local optstring=$1; shift + local oOPTIND=$OPTIND OPTIND=1 + + # Enumerate the arguments. + while getopts "$optstring" arg; do + [[ $arg != '?' ]] && found=1 + + (( quiet + count )) || \ + printf "%s${OPTARG:+ }%s%s" "$arg" "$OPTARG" "$delimitor" + done + OPTARGS=$(( OPTIND - 1 )) + OPTIND=$oOPTIND + + # Any arguments found? + (( count )) && printf "%s" "$OPTARGS" + return $(( ! found )) +} # _____________________________________________________________________ + + + +# |__ ShowHelp __________________________________________________________| +# +# showHelp name description author [option description]... +# +# Generate a prettily formatted usage description of the application. +# +# name Provide the name of the application. +# +# description Provide a detailed description of the application's +# purpose and usage. +# +# option An option the application can take as argument. +# +# description A description of the effect of the preceding option. +# +showHelp() { + + # Check usage. + (( $# < 3 )) || getArgs -q :h "$@" && { + emit -y 'Please provide the name, description, author and options' \ + 'of the application.' + return 1 + } + + # Parse the options. + local appName=$1; shift + local appDesc=${1//+([[:space:]])/ }; shift + local appAuthor=$1; shift + local cols=$(tput cols) + (( cols = ${cols:-80} - 10 )) + + # Figure out what FD to use for our messages. + [[ -t 1 ]]; local fd=$(( $? + 1 )) + + # Print out the help header. + printf "$reset$bold\n" >&$fd + printf "\t\t%s\n" "$appName" >&$fd + printf "$reset\n" >&$fd + printf "%s\n" "$appDesc" | fmt -w "$cols" | sed $'s/^/\t/' >&$fd + printf "\t $reset$bold~ $reset$bold%s\n" "$appAuthor" >&$fd + printf "$reset\n" >&$fd + + # Print out the application options and columnize them. + while (( $# )); do + local optName=$1; shift + local optDesc=$1; shift + printf " %s\t" "$optName" + printf "%s\n" "${optDesc//+( )/ }" | fmt -w "$cols" | sed $'1!s/^/ \t/' + printf "\n" + done | column -t -s $'\t' \ + | sed "s/^\( [^ ]*\)/$bold$green\1$reset/" >&$fd + printf "\n" >&$fd +} # _____________________________________________________________________ + + + +# ______________________________________________________________________ +# |__ Quote _____________________________________________________________| +# +# quote [-e] [argument...] +# +# Output a single string where all arguments are quoted +# such that the string is safe to be passed as shell +# command arguments as though given arguments had been +# passed. +# +# When no arguments are passed; no output is generated. +# +# -e Use backslashes rather than single quotes. +# +quote() { + + # Initialize the defaults. + local arg escape=0 quotedArgs=() + + # Parse the options. + while [[ $1 = -* ]]; do + case $1 in + -e) escape=1 ;; + --) shift; break ;; + esac + shift + done + + # Print out each argument, quoting it properly. + for arg; do + if (( escape )); then + quotedArgs+=("$(printf "%q" "$arg")") + else + quotedArgs+=("$(printf "'%s'" "${arg//"'"/"\\'"}")") + fi + done + + printf '%s\n' "$(IFS=' '; echo "${quotedArgs[*]}")" +} # _____________________________________________________________________ + + + +# ______________________________________________________________________ +# |__ Shorten ___________________________________________________________| +# +# shorten [-p pwd] path [suffix]... +# +# Shorten an absolute path for pretty printing by cutting +# off PWD and replacing HOME by ~. +# +# -p Use the given pathname as the base for relative filenames instead of PWD. +# path The path string to shorten. +# suffix Suffix strings that must be cut off from the end. +# Only the first suffix string matched will be cut off. +# +shorten() { + + # Check usage. + (( $# < 1 )) || getArgs -q :h "$@" && { + emit -y 'Please provide the path to shorten.' + return 1 + } + + # Parse the options. + local suffix path pwd=$PWD + [[ $1 = -p ]] && { pwd=$2; shift 2; } + path=$1; shift + + # Make path absolute. + [[ $path = /* ]] || path=$PWD/$path + + # If the path denotes something that exists; it's easy. + if [[ -d $path ]] + then path=$(cd "$path"; printf "%s" "$PWD") + elif [[ -d ${path%/*} ]] + then path=$(cd "${path%/*}"; printf "%s" "$PWD/${path##*/}") + + # If not, we'll try readlink -m. + elif readlink -m / >/dev/null 2>&1; then + path=$(readlink -m "$path") + + # If we don't have that - unleash the sed(1) madness. + else + local oldpath=/ + while [[ $oldpath != $path ]]; do + oldpath=$path + path=$(sed -e 's,///*,/,g' -e 's,\(^\|/\)\./,\1,g' -e 's,\(^\|/\)[^/]*/\.\.\($\|/\),\1,g' <<< "$path") + done + fi + + # Replace special paths. + path=${path#$pwd/} + path=${path/#$HOME/'~'} + + # Cut off suffix. + for suffix; do + [[ $path = *$suffix ]] && { + path=${path%$suffix} + break + } + done + + printf "%s" "$path" +} # _____________________________________________________________________ + + + +# ______________________________________________________________________ +# |__ InArray ___________________________________________________________| +# +# inArray element array +# +# Checks whether a certain element is in the given array. +# +# element The element to search the array for. +# array This is a list of elements to search through. +# +inArray() { + + # Check usage. + (( $# < 1 )) || getArgs -q :h "$@" && { + emit -y 'Please provide the element to search for and the array' \ + 'to search through.' + return 1 + } + + # Parse the options. + local element + local search=$1; shift + + # Perform the search. + for element + do [[ $element = $search ]] && return 0; done + return 1 +} # _____________________________________________________________________ + + + +# ______________________________________________________________________ +# |__ xpathNodes ________________________________________________________| +# +# xpathNodes query [filename] +# +# Outputs every xpath node that matches the query on a separate line. +# Leading and trailing whitespace is always stripped. +# +# filename The path to the file that contains the document to run the query on. +# query The XPath query to run on the document. +# +xpathNodes() { + local query=$1 filename=$2 + [[ $filename ]] || filename=<(cat) + + { + if xpath -e / <(echo '') >/dev/null 2>&1; then + xpath -e "$query" "$filename" 2>&1 + else + xpath "$filename" "$query" 2>&1 + fi + } | { + read + sed -ne $'s/-- NODE --/\\\n/g' -e 's/^[[:space:]]*\(.*[^[:space:]]\)[[:space:]]*$/\1/p' + } + + return "${PIPESTATUS[0]}" +} + + + +# ______________________________________________________________________ +# |__ HideDebug _________________________________________________________| +# +# hideDebug [ on | off ] +# +# Toggle Bash's debugging mode off temporarily. To hide Bash's debugging +# output for a function, you should have a hideDebug on as its first line +# and hideDebug off as its last. +# +hideDebug() { + + if [[ $1 = on ]]; then + : -- HIDING DEBUG OUTPUT .. + [[ $- != *x* ]]; bashlib_debugWasOn=$? + set +x + elif [[ $1 = off ]]; then + : -- SHOWING DEBUG OUTPUT .. + (( bashlib_debugWasOn )) && \ + set -x + fi +} + +# ______________________________________________________________________ +# |__ StackTrace ________________________________________________________| +# +# stackTrace +# +# Retrieve a mapping of a key from the given map or modify the given map by +# assigning a new value for the given key if stdin is not the terminal. +# +stackTrace() { + + # Some general debug information. + printf "\t$bold%s$reset v$bold%s$reset" "$BASH" "$BASH_VERSION\n" + printf " Was running: $bold%s %s$reset" "$BASH_COMMAND" "$*\n" + printf "\n" + printf " [Shell : $bold%15s$reset] [Subshells : $bold%5s$reset]\n" "$SHLVL" "$BASH_SUBSHELL" + printf " [Locale : $bold%15s$reset] [Runtime : $bold%5s$reset]\n" "$LC_ALL" "${SECONDS}s" + printf "\n" + + # Search through the map. + local arg=0 + for i in ${!FUNCNAME[@]}; do + #if (( i )); then + + # Print this execution stack's location. + printf "$reset $bold-$reset $green" + [[ ${BASH_SOURCE[i+1]} ]] \ + && printf "%s$reset:$green$bold%s" "${BASH_SOURCE[i+1]}" "${BASH_LINENO[i]}" \ + || printf "${bold}Prompt" + + # Print this execution stack's function and positional parameters. + printf "$reset :\t$bold%s(" "${FUNCNAME[i]}" + [[ ${BASH_ARGC[i]} ]] && \ + for (( j = 0; j < ${BASH_ARGC[i]}; j++ )); do + (( j )) && printf ', ' + printf "%s" "${BASH_ARGV[arg]}" + let arg++ + done + + # Print the end of this execution stack's line. + printf ")$reset\n" + #fi + done + printf "\n" + +} # _____________________________________________________________________ + + + + + +# ______________________________________________________________________ +# | | +# | .:: ENTRY POINT ::. | +# |______________________________________________________________________| + +# Make sure this file is sourced and not executed. +(( ! BASH_LINENO )) && { + emit -R "You should source this file, not execute it." + exit 1 +} + +: +: .:: END SOURCING ::. +: ______________________________________________________________________ +: diff --git a/Scripts/checkLocalization b/Scripts/checkLocalization new file mode 100755 index 00000000..255b1557 --- /dev/null +++ b/Scripts/checkLocalization @@ -0,0 +1,60 @@ +#! /usr/bin/env bash +source bashlib + +isIn() { + local key=$1; shift + + for value + do [[ $value = "$key" ]] && return; done +} + +cd "${0%/*}/../../" + +emit "Enumerating localization keys" +code=$(find Classes -type f -exec grep -o 'NSLocalizedString(@"[^"]*"' {} + | sed -n 's/.*\("[^"]*"\).*/\1/p' | sort -bu) +for l in Resources/*.lproj/Localizable.strings; do + k=${l#*/}; k=${k%%/*} + emit " - Found language: ${k%.lproj}" + + lang+=( "$k" ) + lprojLocal+=( "$(sed -n '/\/\/[^"]*\[REMOTE\][^"]*$/!s/^\("[^"]*"\).*/\1/p' "$l" | sort -bu)" ) + lprojAll+=( "$(sed -n 's/^\("[^"]*"\).*/\1/p' "$l" | sort -u)" ) +done + +allhealthy=1 +healthy=1 +echo; emit "Looking for unused localization keys" +for l in "${!lang[@]}"; do + while read; do + (( healthy )) && emit -y "Not used in code or marked '// [REMOTE]':" + allhealthy=0 + healthy=0 + emit -y " ${lang[l]}: ${REPLY##*([[:space:]])} " + done < <(comm -1 -3 <(printf '%s\n' "$code") <(printf '%s\n' "${lprojLocal[l]}")) +done +(( healthy )) && emit "No unused keys." + +healthy=1 +echo; emit "Looking for missing localization keys" +for l in "${!lang[@]}"; do + chealthy=1 + while read; do + (( chealthy )) && emit -y "Used by code:" + allhealthy=0 + chealthy=0 + healthy=0 + emit -r " ${lang[l]}: ${REPLY##*([[:space:]])} " + done < <(comm -2 -3 <(printf '%s\n' "$code") <(printf '%s\n' "${lprojAll[l]}")) + khealthy=1 + while read; do + (( khealthy )) && emit -y "Present in other languages:" + allhealthy=0 + khealthy=0 + healthy=0 + emit -r " ${lang[l]}: ${REPLY##*([[:space:]])} " + done < <(for ol in "${!lang[@]}"; do comm -1 -3 <(printf '%s\n' "${lprojAll[l]}") <(printf '%s\n' "${lprojAll[ol]}"); done | sort -bu) +done +(( healthy )) && emit "No missing keys." + +echo +(( allhealthy )) && emit "All good." || emit -y "Some issues detected." diff --git a/Scripts/convertImages b/Scripts/convertImages new file mode 100755 index 00000000..35907844 --- /dev/null +++ b/Scripts/convertImages @@ -0,0 +1,32 @@ +#! /usr/bin/env bash +source bashlib +shopt -s nullglob + +emit "Converting iTunesArtwork" +icons=( + [29]="Icon-Small.png" + [50]="Icon-Small-50.png" + [58]="Icon-Small@2x.png" + [57]="Icon.png" + [72]="Icon-72.png" + [114]="Icon@2x.png" +) +cd "${0%/*}/../OnePassword" + +for size in "${!icons[@]}"; do + file=${icons[size]} + + emit "$file ($size px)" -- + convert "iTunesArtwork.png" -resize "${size}x${size}" "$file" + emit -$? +done + + +echo +emit "Converting @2x artwork" +for file in !(Icon*)@2x.png; do + emit "${file/@2x}" -- + convert "$file" -resize 50% "${file/@2x}" + emit -$? +done + diff --git a/Scripts/updateDependencies b/Scripts/updateDependencies index 469da869..3440461b 100755 --- a/Scripts/updateDependencies +++ b/Scripts/updateDependencies @@ -4,13 +4,13 @@ cd "${BASH_SOURCE%/*}/.." shopt -s extglob -## Pearl +## LisuUI # ## Submodules that need to be checked out. -dependencies=( External/Pearl External/Pearl:External/{jrswizzle,uicolor-utilities} ) +dependencies=( External/Pearl External/Pearl:External/jrswizzle External/Pearl:External/uicolor-utilities ) ## Custom migration. -# Nothing yet. +# None yet. ################################################################################