通知センターの通知を全部消す

通知の種類をアラートからバナーに変更するとすぐに消えてしまって見逃しがありそう…ってことで、だいたいの通知はアラートにして、自動的に消えないようにしています。 ですが、ちょっと離席したときに通知が溜まっていると、それを全部ポチポチ消すのは面倒ですね。

そこで全部消すためのスクリプトをAlfred workflowにしています。 動作イメージはこんな感じ。

f:id:tomorrowkey:20180818144621g:plain

シュッと消えてくれて便利です。 こちらからダウンロードできますが、macOSの設定を英語にしていないと動きません。

github.com

ここのClose閉じるに変更すると日本語でも動くので、その場合はビルドしなおして alfredworkflowファイルを作り直してください。

https://github.com/tomorrowkey/alfred-workflows/blob/master/clear_notification/clear.applescript#L5

cloneしていないリポジトリのmasterのハッシュを調べる

git-ls-remote を使う

$ git ls-remote https://github.com/tomorrowkey/adb-peco master
788d83985e44f747a785cb948ac75fe4a048862d    refs/heads/master

もちろんgithubじゃなくてもいいからandroidのframework/baseのmasterを取得する場合はこんな感じ

$ git ls-remote https://android.googlesource.com/platform/frameworks/base master
d68f003c67ca6364202a57f0c695012d4ea4571e    refs/heads/master

オプションなど

$ man git-ls-remote
GIT-LS-REMOTE(1)                                                                                                                                              Git Manual                                                                                                                                             GIT-LS-REMOTE(1)

NAME
       git-ls-remote - List references in a remote repository

SYNOPSIS
       git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]
                     [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]
                     [--symref] [<repository> [<refs>...]]

DESCRIPTION
       Displays references available in a remote repository along with the associated commit IDs.

OPTIONS
       -h, --heads, -t, --tags
           Limit to only refs/heads and refs/tags, respectively. These options are not mutually exclusive; when given both, references stored in refs/heads and refs/tags are displayed.

       --refs
           Do not show peeled tags or pseudorefs like HEAD in the output.

       -q, --quiet
           Do not print remote URL to stderr.

       --upload-pack=<exec>
           Specify the full path of git-upload-pack on the remote host. This allows listing references from repositories accessed via SSH and where the SSH daemon does not use the PATH configured by the user.

       --exit-code
           Exit with status "2" when no matching refs are found in the remote repository. Usually the command exits with status "0" to indicate it successfully talked with the remote repository, whether it found any matching refs.

       --get-url
           Expand the URL of the given remote repository taking into account any "url.<base>.insteadOf" config setting (See git-config(1)) and exit without talking to the remote.

       --symref
           In addition to the object pointed by it, show the underlying ref pointed by it when showing a symbolic ref. Currently, upload-pack only shows the symref HEAD, so it will be the only one shown by ls-remote.

       --sort=<key>
           Sort based on the key given. Prefix - to sort in descending order of the value. Supports "version:refname" or "v:refname" (tag names are treated as versions). The "version:refname" sort order can also be affected by the "versionsort.suffix" configuration variable. See git-for-each-ref(1) for more sort options,
           but be aware keys like committerdate that require access to the objects themselves will not work for refs whose objects have not yet been fetched from the remote, and will give a missing object error.

       -o <option>, --server-option=<option>
           Transmit the given string to the server when communicating using protocol version 2. The given string must not contain a NUL or LF character. When multiple --server-option=<option> are given, they are all sent to the other side in the order listed on the command line.

       <repository>
           The "remote" repository to query. This parameter can be either a URL or the name of a remote (see the GIT URLS and REMOTES sections of git-fetch(1)).

       <refs>...
           When unspecified, all references, after filtering done with --heads and --tags, are shown. When <refs>... are specified, only references matching the given patterns are displayed.

EXAMPLES
           $ git ls-remote --tags ./.
           d6602ec5194c87b0fc87103ca4d67251c76f233a        refs/tags/v0.99
           f25a265a342aed6041ab0cc484224d9ca54b6f41        refs/tags/v0.99.1
           7ceca275d047c90c0c7d5afb13ab97efdf51bd6e        refs/tags/v0.99.3
           c5db5456ae3b0873fc659c19fafdde22313cc441        refs/tags/v0.99.2
           0918385dbd9656cab0d1d81ba7453d49bbc16250        refs/tags/junio-gpg-pub
           $ git ls-remote http://www.kernel.org/pub/scm/git/git.git master pu rc
           5fe978a5381f1fbad26a80e682ddd2a401966740        refs/heads/master
           c781a84b5204fb294c9ccc79f8b3baceeb32c061        refs/heads/pu
           $ git remote add korg http://www.kernel.org/pub/scm/git/git.git
           $ git ls-remote --tags korg v\*
           d6602ec5194c87b0fc87103ca4d67251c76f233a        refs/tags/v0.99
           f25a265a342aed6041ab0cc484224d9ca54b6f41        refs/tags/v0.99.1
           c5db5456ae3b0873fc659c19fafdde22313cc441        refs/tags/v0.99.2
           7ceca275d047c90c0c7d5afb13ab97efdf51bd6e        refs/tags/v0.99.3

SEE ALSO
       git-check-ref-format(1).

GIT
       Part of the git(1) suite

Git 2.18.0                                                                                                                                                    06/21/2018                                                                                                                                             GIT-LS-REMOTE(1)

配列の要素を一意にする

RubyでいうところのArray#uniqみたいなもの

let array = [1, 1, 2, 4, 1, 3, 2]
array.enumerated().compactMap({ index, item in array.index(of: item) == index ? item : nil })

それぞれの「index」と「arrayからindex(of:) で取得したindex」が一致した場合のみ要素が残るようにしている。 つまり最初に出現した要素だけが残るようになっている。 毎回書くののも面倒なので、extensionしておくと便利

Closureの即時実行を使ったスコープの切り分け

Swiftのletはimmutableな変数宣言で、一度値を入れたらその後に変更することができない。

let hoge = "hoge"
hoge = "fuga" // コンパイルエラー

これは変数宣言のときに値を入れないといけない、という制限ではなく、その変数が使われるまでに値が入っていれば問題ない。 ただし、その場合は型の宣言を省略できない。

let hoge: String
hoge = "hoge" // OK

「その変数が使われるまでに値が入っていれば問題ない。」というのは例えばif文やswitch文を使っても大丈夫

let hoge: String
if arc4random() % 2 == 0 {
    str = "even"
} else {
    str = "odd"
}
debugPrint(str) // "even" もしくは "odd"が出力される

たまに処理が複雑で使い捨て変数を割り当てないといけないことがある。

let array = Array(1...10)
var sum = 0
array.forEach({ sum += $0 })
let average = sum / array.count

このときsum変数は一時的な変数で、averageを求めたら必要なくなる。このexampleではそんなことないんだけど、使い捨ての変数名を考えるが面倒で、手が止まってしまうことがしばしばあり、違うスコープを切りたい時に有効なのがクロージャだ。

let array = Array(1...10)
let average: Int = {
    var sum = 0
    array.forEach({ sum += $0 })
    return sum / array.count
}()

クロージャ内部は別のスコープなので、使い捨ての変数は本当に使いたい部分でだけ有効になる。 まぁそもそもこのexampleではreduceを使えばいい話なんだけど…

let average = array.reduce(0) { sum, i in sum + i } / array.count

Viewに関するコードを書いていると使い捨ての変数を定義したくなることがあるので、そういうときに使うと便利。

forEachでインデックスを使いたい

配列をすべて舐めるような処理をする時はforEachを使うけど、この時indexを使うことができない

let array = ["a", "b", "c", "d"]
array.forEach { string in
  debugPrint(string)
}

そんなときはArray#enumerated() を使えばindexも使うことができる

let array = ["a", "b", "c", "d"]
array.enumerated().forEach({ index, string in
    debugPrint("\(index): \(string)")
})

// "0: a"
// "1: b"
// "2: c"
// "3: d"

UITextFieldで入力文字を制限する

UITextFieldDelegate を使う

textField(_:shouldChangeCharactersIn:replacementString:) - UITextFieldDelegate | Apple Developer Documentation

例えばIntにパースできる値だけにしたければ、次のようなコードになる

class ViewController: UIViewController, UITextFieldDelegate {
    @IBOutlet weak var textField: UITextField!

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        return Int(string) != nil
    }
}

ただ、このdelegateメソッドの引数である string は入力された値だけなので、UITextFieldに入る値を数値だけに制限したい場合は、これだけでは不十分。 range 引数に、UITextField のキャレットなどの文字選択位置が渡されるので、それで置換してあげればいい。

class ViewController: UIViewController, UITextFieldDelegate {
    @IBOutlet weak var textField: UITextField!

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        if let currentString = textField.text, let _range = Range(range, in: currentString) {
            let newString = currentString.replacingCharacters(in: _range, with: string)
            return Int(newString) != nil
        } else {
            return false
        }
    }
}

コマンドラインの実行結果を監視する

コマンドラインの実行結果を監視したいんだと

  • watchだと履歴が見れない
  • whileだと全部垂れ流しで全部のデータを見るのがだるい

コマンドラインの実行結果が変わったときだけに表示してほしい〜〜って思ったんだけど、watchもwhileも微妙だったのでチョコチョコかいた そういうコマンドありそうなんだけど知らないなあ

while do
  sleep 1
  c=`date +"%Y-%m-%d %H:%M"`
  if [ $c != $d ]; then
    date
    echo $c
    echo '-------------------------------------------------------------------'
  fi
  d=$c
done

こんな感じに標準出力が変わったときに表示される

2018年 3月13日 火曜日 07時40分00秒 JST
2018-03-13 07:40
-------------------------------------------------------------------
2018年 3月13日 火曜日 07時41分00秒 JST
2018-03-13 07:41
-------------------------------------------------------------------
2018年 3月13日 火曜日 07時42分00秒 JST
2018-03-13 07:42
-------------------------------------------------------------------
2018年 3月13日 火曜日 07時43分00秒 JST
2018-03-13 07:43
-------------------------------------------------------------------
2018年 3月13日 火曜日 07時44分00秒 JST
2018-03-13 07:44
-------------------------------------------------------------------