Mac初期設定 for フルスタックエンジニア
【2022/12/18更新】
- Dropboxのフォルダ変更
【2022/09/09更新】
- Monterey対応
【2021/02/14更新】
- Catalina(zsh)対応にしました。
- 使ってるやつとかインストールするものとか最新にしました。
【2023/03/29更新】
- Flutter追加
- ~/.zhrc晒す
- ~/.zprofile晒す
//------------------------------------------------------------------------------------
備忘録。
フルスタックエンジニアな僕がMacを新しく買った時にやること。
構成管理全部自動でできたらいいのに&できそうとは思うけど数年に1回だしなぁ。
秘密鍵とか設定とかはだいたいDropboxに置いてあります。
WebやらApp Storeやらからインストールするもの
・開発以外
- Google Chrome - The Fast & Secure Web Browser Built to be Yours
- Alfred - Productivity App for macOS
- Spectacle
- HyperSwitch
- AppCleaner for Mac - 無料・ダウンロード
- Dropbox.com
- One platform to connect | Zoom
- https://apps.apple.com/jp/app/display-menu/id549083868?mt=12
- https://tryshift.com/
- https://www.office.com/
- https://matthewpalmer.net/vanilla/
・開発系
- Download Android Studio & App Tools - Android Developers
- Install Docker Desktop on Mac | Docker Docs
- Sourcetree - 無料の Git & Mercurial クライアント | Atlassian
- Download Visual Studio Code - Mac, Linux, Windows
- 「Xcode」をMac App Storeで
ターミナルでやること
# zsh ln -s ~/Library/CloudStorage/Dropbox/zsh/zprofile ~/.zprofile ln -s ~/Library/CloudStorage/Dropbox/zsh/zshrc ~/.zshrc # vim echo -e -n ':syntax on\n' >> ~/.vimrc # ssh ln -s ~/Library/CloudStorage/Dropbox/ssh ~/.ssh # homebrew xcode-select --install sudo xcodebuild -license /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" brew doctor # nodeenv brew install nodenv nodenv install -l nodenv install X.X.X # 任意のバージョンをインストール nodenv rehash nodenv global X.X.X # rbenv brew install rbenv ruby-build rbenv install $(rbenv install -l | grep -v - | tail -1) rbenv global $(rbenv versions | grep -v - | tail -1) # Node.js / yarn brew install yarn # AWS brew install awscli ln -s ~/Library/CloudStorage/Dropbox/aws ~/.aws curl "https://s3.amazonaws.com/session-manager-downloads/plugin/latest/mac/session-manager-plugin.pkg" -o "session-manager-plugin.pkg" sudo installer -pkg session-manager-plugin.pkg -target / sudo ln -s /usr/local/sessionmanagerplugin/bin/session-manager-plugin /usr/local/bin/session-manager-plugin rm session-manager-plugin.pkg # Git brew install git-lfs # VSCode rm -rf ~/Library/Application\ Support/Code/User mkdir -p ~/Library/Application\ Support/Code/User ln -s ~/Library/CloudStorage/Dropbox/code/* ~/Library/Application\ Support/Code/User # Android brew install bundletool # Xcode defaults write com.apple.dt.Xcode ShowBuildOperationDuration YES # act brew install act # Mint brew install mint # jq brew install jq # Firebase curl -sL https://firebase.tools | bash # Flutter brew tap leoafarias/fvm brew install fvm
~/.zprofile
# License : MIT # http://mollifier.mit-license.org/ ######################################## # 環境変数 export LANG=ja_JP.UTF-8 # 色を使用出来るようにする autoload -Uz colors colors # ヒストリの設定 HISTFILE=~/.zsh_history HISTSIZE=1000000 SAVEHIST=1000000 setopt AUTO_MENU # プロンプト PROMPT="[%F{cyan}%~%f]$ " RPROMPT="" # 単語の区切り文字を指定する autoload -Uz select-word-style select-word-style default # ここで指定した文字は単語区切りとみなされる # / も区切りと扱うので、^W でディレクトリ1つ分を削除できる zstyle ':zle:*' word-chars " /=;@:{},|" zstyle ':zle:*' word-style unspecified # 補完 autoload -U compinit compinit zstyle ':completion::complete:*' use-cache true zstyle ':completion:*:default' menu select true zstyle ':completion:*:default' menu select=1 #補完でカラーを使用する zstyle ':completion:*' list-colors "${LS_COLORS}" #コマンドにsudoを付けても補完 zstyle ':completion:*:sudo:*' command-path /usr/local/sbin /usr/local/bin /usr/sbin /usr/bin /sbin /bin /usr/X11R6/bin #何も入力されていないときのTABでTABが挿入されるのを抑制 zstyle ':completion:*' insert-tab false # フローコントロールを無効にする setopt no_flow_control # Ctrl+Dでzshを終了しない setopt ignore_eof # '#' 以降をコメントとして扱う setopt interactive_comments # 同じコマンドをヒストリに残さない setopt hist_ignore_all_dups ######################################## # sudo の後のコマンドでエイリアスを有効にする alias sudo='sudo ' # グローバルエイリアス alias -g L='| less' alias -g G='| grep' # C で標準出力をクリップボードにコピーする # mollifier delta blog : http://mollifier.hatenablog.com/entry/20100317/p1 if which pbcopy >/dev/null 2>&1 ; then # Mac alias -g C='| pbcopy' elif which xsel >/dev/null 2>&1 ; then # Linux alias -g C='| xsel --input --clipboard' elif which putclip >/dev/null 2>&1 ; then # Cygwin alias -g C='| putclip' fi ######################################## # OS 別の設定 case ${OSTYPE} in darwin*) #Mac用の設定 export CLICOLOR=1 alias ls='ls -G -F' ;; linux*) #Linux用の設定 alias ls='ls -F --color=auto' ;; esac # vim:set ft=zsh:
~/.zprofile
# terminal alias ls="ls -G" alias ll="ls -alG" # homebrew eval "$(/opt/homebrew/bin/brew shellenv)" # nodenv eval "$(nodenv init -)" export PATH="$HOME/.nodenv/bin:$PATH" # Node export NODE_OPTIONS=--dns-result-order=ipv4first # rbenv if which rbenv > /dev/null; then eval "$(rbenv init -)"; fi export PATH="$HOME/.rbenv/bin:$PATH" eval "$(rbenv init -)" # Java export JAVA_HOME="/Applications/Android Studio.app/Contents/jre/Contents/Home" export PATH="$JAVA_HOME/bin:$PATH" # Android export ANDROID_HOME=$HOME/Library/Android/sdk export PATH="$ANDROID_HOME/build-tools/30.0.3:$PATH" export PATH="$ANDROID_HOME/platform-tools:$PATH" # Flutter alias flutter="fvm flutter" export PATH="$HOME/fvm/default/bin:$PATH" export PATH="$PATH":"$HOME/.pub-cache/bin" # JSC export PATH="/System/Library/Frameworks/JavaScriptCore.framework/Versions/A/Helpers:$PATH" export LANG=en_US.UTF-8
Xcode10 Abort trap:6
たまには書く。
To iOSえんじにあーな皆様
Xcode10にすると以下のコードが使えなくなる模様だぉ
なんでだかわからんけど、調べる暇はないんだぉ
import UIKit final class FooViewController: UIViewController { init() { super.init(nibName: nil, bundle: nil) } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } }
こっちならおっけーらしいけどさーけどさー
convenience initってinitじゃないじゃん?
import UIKit final class FooViewController: UIViewController { convenience init() { self.init(nibName: nil, bundle: nil) } }
【Cordova】 bump
プラグインとかあるけど、よくよく考えたら、fastlane使ってりゃRubyで書けばいいよね。
なお、Unity / Cocos2d-x に加え、Cordova pluginの作り方も覚えた。
lane :bump do require 'rexml/document' doc = REXML::Document.new(File.read('../config.xml')) element = doc.elements['widget'] element.attributes['android-versionCode'] = element.attributes['android-versionCode'].to_i + 1 element.attributes['ios-CFBundleVersion'] = element.attributes['ios-CFBundleVersion'].to_i + 1 File.write('../config.xml', doc) end
【WPF】KeyBinding with TriggerAction(Data Binding対応版)
はい。昨日こんなの書きました。動きませんでした。
参考記事によるとTriggerBaseはFreeazableだから、当然TriggerBaseを継承しているやつなら問題ないと思ったんですけどね。ICommandを実装してるとだめらしい。
というわけで書き直しました。
InputBindingTrigger
using System; using System.Diagnostics; using System.Windows; using System.Windows.Input; using System.Windows.Interactivity; namespace Hoge.Trigger { public class InputBindingTrigger : TriggerBase<FrameworkElement> { public static readonly DependencyProperty InputBindingProperty = DependencyProperty.Register("InputBinding", typeof(InputBinding) , typeof(InputBindingTrigger) , new UIPropertyMetadata(null)); public InputBinding InputBinding { get => (InputBinding)GetValue(InputBindingProperty); set => SetValue(InputBindingProperty, value); } private InputBindingCommand command = new InputBindingCommand(); protected override void OnAttached() { if (InputBinding == null) { base.OnAttached(); return; } InputBinding.Command = command; command.OnExecute += Command_OnExecute; if (AssociatedObject.Focusable) AssociatedObject.InputBindings.Add(InputBinding); else { FrameworkElement root = null; AssociatedObject.Loaded += delegate { root = GetRootElement(AssociatedObject); if (!root.InputBindings.Contains(InputBinding)) root.InputBindings.Add(InputBinding); }; AssociatedObject.Unloaded += delegate { root.InputBindings.Remove(InputBinding); }; } base.OnAttached(); } private FrameworkElement GetRootElement(FrameworkElement frameworkElement) { var parent = frameworkElement.Parent as FrameworkElement; if (parent == null) { Debug.Assert(frameworkElement.Focusable); frameworkElement.Focus(); return frameworkElement; } return GetRootElement(parent); } protected override void OnDetaching() { command.OnExecute -= Command_OnExecute; base.OnDetaching(); } private void Command_OnExecute(object parameter) => InvokeActions(parameter); } internal class InputBindingCommand : ICommand { public event EventHandler CanExecuteChanged = delegate { }; public Action<object> OnExecute = delegate { }; public bool CanExecute(object parameter) => true; public void Execute(object parameter) => OnExecute.Invoke(parameter); } }
ICommandを実装するのやめただけですね。
あと、RootElement取得するように変えてるっす。ので、ちょっとxamlが変わります。
ルート要素のFocusableをTrueに。
TriggerActionはTrigger.Actionsに。
なお、TriggerActionは前回用意したやつなので省略。
<Window x:Class="Hoge.Views.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:action="clr-namespace:Hoge.Action" xmlns:trigger="clr-namespace:Hoge.Trigger" Focusable="True"> <Grid> <i:Interaction.Triggers> <trigger:InputBindingTrigger> <trigger:InputBindingTrigger.InputBinding> <KeyBinding Modifiers="Ctrl" Key="N"/> </trigger:InputBindingTrigger.InputBinding> <trigger:InputBindingTrigger.Actions> <action:ShowFolderBrowserDialogAction Description="選択せーや" SelectedPath="{Binding SelectedPath.Value, Mode=OneWayToSource}" /> </trigger:InputBindingTrigger.Actions> </trigger:InputBindingTrigger> </i:Interaction.Triggers> </Grid> </Window>
参考:
qiita.com
【WPF】KeyBinding with TriggerAction
追記。これ、このままじゃData Binding動かへん。書き直します。。
KeyBindingで実行対象がCommandなら別になんてことないんですけどね。
TriggerAction使う場合ね。
いつも通りおもむろに以下を作りましょう。
using System; using System.Windows; using System.Windows.Input; using System.Windows.Interactivity; namespace Hoge.Action { public class InputBindingTrigger : TriggerBase<FrameworkElement>, ICommand { public static readonly DependencyProperty InputBindingProperty = DependencyProperty.Register("InputBinding", typeof(InputBinding) , typeof(InputBindingTrigger) , new UIPropertyMetadata(null)); public InputBinding InputBinding { get => (InputBinding)GetValue(InputBindingProperty); set => SetValue(InputBindingProperty, value); } public event EventHandler CanExecuteChanged = delegate { }; protected override void OnAttached() { if (InputBinding != null) { InputBinding.Command = this; AssociatedObject.InputBindings.Add(InputBinding); } base.OnAttached(); } public bool CanExecute(object parameter) => true; public void Execute(object parameter) => InvokeActions(parameter); } }
使い方
こんなTriggerActionが用意してあります。フォルダ選択ダイアログですね。
namespace Hoge.Action { /// <summary> /// FolderBrowserDialog Confirmation /// </summary> public sealed class FolderBrowserDialogConfirmation : Confirmation { public Boolean? ShowNewFolderButton { get; set; } public String SelectedPath { get; set; } public Environment.SpecialFolder? RootFolder { get; set; } public String Description { get; set; } public Object Tag { get; set; } } /// <summary> /// FolderBrowserDialog表示アクション /// </summary> public sealed partial class ShowFolderBrowserDialogAction { public Boolean? ShowNewFolderButton { get => (Boolean?)GetValue(ShowNewFolderButtonProperty); set => SetValue(ShowNewFolderButtonProperty, value); } private static readonly DependencyProperty ShowNewFolderButtonProperty = DependencyProperty.Register("ShowNewFolderButton", typeof(Boolean?), typeof(ShowFolderBrowserDialogAction), new PropertyMetadata(null)); public String SelectedPath { get => (String)GetValue(SelectedPathProperty); set => SetValue(SelectedPathProperty, value); } private static readonly DependencyProperty SelectedPathProperty = DependencyProperty.Register("SelectedPath", typeof(String), typeof(ShowFolderBrowserDialogAction), new PropertyMetadata(null)); public Environment.SpecialFolder? RootFolder { get => (Environment.SpecialFolder)GetValue(RootFolderProperty); set => SetValue(RootFolderProperty, value); } private static readonly DependencyProperty RootFolderProperty = DependencyProperty.Register("RootFolder", typeof(Environment.SpecialFolder), typeof(ShowFolderBrowserDialogAction), new PropertyMetadata(null)); public String Description { get => (String)GetValue(DescriptionProperty); set => SetValue(DescriptionProperty, value); } private static readonly DependencyProperty DescriptionProperty = DependencyProperty.Register("Description", typeof(String), typeof(ShowFolderBrowserDialogAction), new PropertyMetadata(null)); public Object Tag { get => GetValue(TagProperty); set => SetValue(TagProperty, value); } private static readonly DependencyProperty TagProperty = DependencyProperty.Register("Tag", typeof(Object), typeof(ShowFolderBrowserDialogAction), new PropertyMetadata(null)); } public sealed partial class ShowFolderBrowserDialogAction : TriggerAction<DependencyObject> { private static readonly FolderBrowserDialogConfirmation NullObject = new FolderBrowserDialogConfirmation(); protected override void Invoke(object parameter) { var param = parameter as InteractionRequestedEventArgs; var confirmation = param == null ? NullObject : param.Context as FolderBrowserDialogConfirmation; var dialog = GenerateDialog(confirmation); if (dialog.ShowDialog() == DialogResult.OK) { confirmation.Confirmed = true; ApplyDialogPropertyValues(confirmation, dialog); } else { confirmation.Confirmed = false; } param?.Callback(); } private FolderBrowserDialog GenerateDialog(FolderBrowserDialogConfirmation confirmation) { var dlg = new FolderBrowserDialog(); dlg.ShowNewFolderButton = confirmation.ShowNewFolderButton ?? ShowNewFolderButton ?? dlg.ShowNewFolderButton; dlg.RootFolder = confirmation.RootFolder ?? RootFolder ?? dlg.RootFolder; dlg.Description = confirmation.Description ?? Description ?? dlg.Description; dlg.Tag = confirmation.Tag ?? Tag ?? dlg.Tag; SelectedPath = string.Empty; return dlg; } private void ApplyDialogPropertyValues(FolderBrowserDialogConfirmation n, FolderBrowserDialog dlg) { if (n != NullObject) { n.ShowNewFolderButton = dlg.ShowNewFolderButton; n.SelectedPath = dlg.SelectedPath; n.RootFolder = dlg.RootFolder; n.Description = dlg.Description; n.Tag = dlg.Tag; } ShowNewFolderButton = dlg.ShowNewFolderButton; SelectedPath = dlg.SelectedPath; RootFolder = dlg.RootFolder; Description = dlg.Description; Tag = dlg.Tag; } } }
んで、xaml。コードビハインドとViewModelは省略。ReactiveProperty使ってます。
<Window x:Class="Hoge.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:action="clr-namespace:HogeAction" mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800"> <Grid> <i:Interaction.Triggers> <action:InputBindingTrigger> <action:InputBindingTrigger.InputBinding> <KeyBinding Modifiers="Ctrl" Key="N"/> </action:InputBindingTrigger.InputBinding> <action:ShowFolderBrowserDialogAction Description="フォルダを選択してください" SelectedPath="{Binding SelectedPath.Value, Mode=OneWayToSource}" /> </action:InputBindingTrigger> </i:Interaction.Triggers> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition /> </Grid.RowDefinitions> <Menu Grid.Row="0" > <MenuItem Header="ファイル(_F)"> <MenuItem Header="新規(_N)" InputGestureText="Ctrl+N"> <i:Interaction.Triggers> <i:EventTrigger EventName="Click"> <action:ShowFolderBrowserDialogAction Description="フォルダを選択してください" SelectedPath="{Binding SelectedPath.Value, Mode=OneWayToSource}" /> </i:EventTrigger> </i:Interaction.Triggers> </MenuItem> </MenuItem> </Menu> </Grid> </Window>
【C#】【Google Cloud Vision API】拡張
何に使うのかはわからない。
とりあえずSelectManyの繰り返しがひどかったので用意してみた。
何に使うのかはわからない。
ぶっちゃけTextAnnotationの仕様がよくわかってない。。
TextAnnotation.Text.Split('\n')とBlocks.Textが一致してほしいんだけどなぁ。。
using Google.Cloud.Vision.V1; using System.Linq; public static class CloudVisionEx { // TextAnnotation → Page → Block → Paragraph → Word → Symbol → Text public static Block[] Blocks(this TextAnnotation textAnnotation) => textAnnotation.Pages.SelectMany(x => x.Blocks).ToArray(); public static Paragraph[] Paragraphs(this TextAnnotation textAnnotation) => textAnnotation.Pages.SelectMany(x => x.Paragraphs()).ToArray(); public static Paragraph[] Paragraphs(this Page page) => page.Blocks.SelectMany(x => x.Paragraphs).ToArray(); public static Word[] Words(this TextAnnotation textAnnotation) => textAnnotation.Pages.SelectMany(x => x.Words()).ToArray(); public static Word[] Words(this Page page) => page.Blocks.SelectMany(x => x.Words()).ToArray(); public static Word[] Words(this Block block) => block.Paragraphs.SelectMany(x => x.Words).ToArray(); public static Symbol[] Symbols(this TextAnnotation textAnnotation) => textAnnotation.Pages.SelectMany(x => x.Symbols()).ToArray(); public static Symbol[] Symbols(this Page page) => page.Blocks.SelectMany(x => x.Symbols()).ToArray(); public static Symbol[] Symbols(this Block block) => block.Paragraphs.SelectMany(x => x.Symbols()).ToArray(); public static Symbol[] Symbols(this Paragraph paragraph) => paragraph.Words.SelectMany(x => x.Symbols).ToArray(); public static string[] Text(this TextAnnotation textAnnotation) => textAnnotation.Pages.SelectMany(x => x.Text()).ToArray(); public static string[] Text(this Page page) => page.Blocks.SelectMany(x => x.Text()).ToArray(); public static string[] Text(this Block block) => block.Paragraphs.Select(x => x.Text()).ToArray(); public static string Text(this Paragraph paragraph) => string.Join(string.Empty, paragraph.Words.Select(x => x.Text())); public static string Text(this Word word) => string.Join(string.Empty, word.Symbols.SelectMany(x => x.Text)); }
【WPF】親からの比率でいろいろ指定したい、Data Binding, Prism, Reactive
ずーっと何年もこのブログのアクセスランキングTOP5は全部C#の記事なんですぉ。
ということでたまにはC#だぉ。
はい、表題の通り。例えば親の幅の半分の幅にしたいとかいうことあるよね。
Gridとかならさあれだけどさ。Canvas想定ね、Canvas。
親のActualWidthを取ってこないとだめなケースの場合に使えるかと?VMでそんなもん持ちたくないやん?
はい、いつも通りおもむろに以下のクラスを作りましょう。OneWay前提なのでConvertBackは適当。
using System; using System.Globalization; using System.Windows.Data; namespace Hoge.Converter { public sealed class RatioConverter : IMultiValueConverter { public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) => (double)values[0] * (double)values[1]; public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) => null; } }
で、VM
using Prism.Mvvm; using Reactive.Bindings; using Reactive.Bindings.Extensions; namespace Hoge.Controls { /// <summary> /// View model for HogeControl /// </summary> public sealed partial class HogeControlVM: BindableBase { public ReadOnlyReactiveProperty<double> WidthRatioProperty { get; } private double Width { get => width; set => SetProperty(ref width, value); } private double width; } public partial class HogeControlVM { public HogeControlVM() { WidthRatioProperty = this.ObserveProperty(x => x.Width).ToReadOnlyReactiveProperty(); Width = 0.5; } } }
コードビハインドは省略で、View
<UserControl x:Class="Hoge.Controls.HogeControl" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:c="clr-namespace:Hoge.Converter" mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800"> <UserControl.Resources> <c:RatioConverter x:Key="Ratio" /> </UserControl.Resources> <Canvas Name="Canvas"> <TextBox Text="Hogeeee"> <TextBox.Width> <MultiBinding Converter="{StaticResource Ratio}"> <Binding ElementName="Canvas" Path="Width" /> <Binding Path="WidthRatioProperty.Value" /> </MultiBinding> </TextBox.Width> </TextBox> </Canvas> </UserControl>
IDE使わずに書いてるから動かなかったらごめんちゃい?