Today I Learned

A Hashrocket project

159 posts about #workflow

Tmux Attach Sessions with Working Directory

Your Tmux working directory is the root directory of the session. You can figure out what it is by opening a new window or pane in your session. The directory you start in is your working directory.

Sometimes it’s not the best directory for the type of project you’re developing. For instance, it could be set to the root directory of an umbrella app, when you’re working exclusively in one of the subdirectories.

Reset it with the -c flag:

$ tmux attach-session -t my_session -c ~/my_project

Convert .mov to .gif with ffmpeg

Sometimes putting a gif in a pull request is really helpful for reviewers. If you’ve recorded a movie on an iOS simulator with xcrun simctl or just QuickTime, it’s very simple to convert them to animated .gifs

Example:

ffmpeg -i screen_recording.mov \
       -s 415x925 \
       -pix_fmt rgb24 \
       -r 10 \
       -f gif \
       screen_recording.gif

Now it would be nice to have a function that could extract the video dimensions automatically 🤔 mdls 🤯

1 function gif-mov() {
2   movie=$1
3   height=$(mdls -name kMDItemPixelHeight ${movie} | grep -o '[0-]\+')
4   width=$(mdls -name kMDItemPixelWidth ${movie} | grep -o '[0-9]\+')
5   dimensions="${width}x${height}"
6   ffmpeg -i ${movie} -s ${dimensions} -pix_fmt rgb24 -r 10 -f gif ${movie}.gif
7 }

Usage:

$ gif-mov ~/Desktop/cool-screen-recording.mov

Mechanical Keyboard DIP Switches

I’ve owned a WASD keyboard for a while but totally forgot about the DIP switches on the bottom. What’s a DIP switch? From Wikipedia:

A DIP switch is a manual electric switch that is packaged with others in a group in a standard dual in-line package (DIP). The term may refer to each individual switch, or to the unit as a whole. This type of switch is designed to be used on a printed circuit board along with other electronic components and is commonly used to customize the behavior of an electronic device for specific situations.

DIP switch

On a WASD V2 87-key, these switches let you enable Mac mode (switch command and option), swap caps lock with CTRL, activate function commands, and more. These can be set in the OS or via different applications, but setting them at the hardware level is very convenient.

DIP Switch

Change Mechanical Keyboard Keycaps Faster ⌨️

I change the keys on my mechanical keyboards often. Sometimes I’m upgrading from stock, or trying an experiment, or just pursuing a look. It’s a reality of being really into keyboards.

Something I’ve learned along the way: removing all your old caps at once is a bad idea. When you do this, you have to figure out where every key goes. Some keycaps have a code on the underside telling you the row it belongs to, most do not. I end up pulling up my Mac virtual keyboard, or looking at another keyboard, to sort it out.

A better techique: take the new keys and line them up in the correct order for each row. Some keycaps ship in separate rows, making this easy. If that’s the case, slide each row out of its shrinkwrap like a sleeve of Thin Mints.

Then, change one row at a time. Remove all the keycaps in one row, and then put all the new ones in place. This is fast, foolproof, and if you get interrupted in between rows, you still have a functioning keyboard.

image

Proposing new time on Google Calendar invitations

Today I learned that we can respond to an invitation using google calendar proposing a new time. Check this out:

First when we open an invitation on gmail I can hit the link more options:

image

This will open the event on google calendar. Then we can expand more options with the caret down and hit Propose a new time.

image

Finally choose a time and send it back to the event owner. And that’s how they will receive our request to change the event time:

image

Pivotal Tracker Advanced Search by Owner

On a big project, Pivotal Tracker contains a wealth of data. Let’s use it!

Today I filtered all the stories assigned to my teammate with the owner keyword:

owner, owned_by
owner: “Obi Wan Kenobi”
Search using the full name, initials, the username, user id or part of the user’s name.

This filtered out hundreds of stories, leaving the four in progress that I care about.

Here’s the official advanced search guide. Try a new keyword today!

https://www.pivotaltracker.com/help/articles/advanced_search/

Research Software Alternatives

Today I discovered AlternativeTo, which provides ‘crowdsourced software recommendations’. It’s available here:

https://alternativeto.net/

With this resource you can find alternatives to websites, tools, operating systems, and more, and learn about each alternative you find.

For reference, I checked out the results for open source alternatives to Ruby. The list includes no-brainers like Python, JavaScript, and Java, but also Go, C, and Lua. If I were a CTO who didn’t know Ruby and needed to quickly understand its position in the ecosystem, this would be a pretty useful starting point.

image

Zoom Hotkeys to Toggle Audio and Video 🎛

Zoom users, two new hotkeys for you on Mac: CMD-SHIFT-A to toggle audio and CMD-SHIFT-V to toggle video. The ability to control my A/V presentation in long video calls makes these hotkeys worth the muscle memory investment.

Zoom has another handy audio feature in preferences: temporarily unmute by pressing the spacebar. This is perfect for standups, where I mostly want to be muted, but need to be able to unmute quickly for short periods of time.

Dash Docset Keywords 🗝

Dash has a customizable keyword for each Docset. Here are the defaults for a random Hashrocket collection*:

image

These keywords scope search results to one Docset; use one in the Dash search bar like so:

elixir:String.split

And from Alfred:

dash elixir:String.split

This is useful when you have many Docsets, and are sure where you want to look, which should be true almost all the time. It’s nice when using two complementary technologies like Elixir and Elm that share a function namespace (such as String.split).

* Also note: this list order can be changed, as noted in the table header. Move libraries you use often above those you use rarely.

Dash Find in Page 🔎

To build upon my earlier post, Integrate Alfred and Dash: Dash supports find-in-page search via a whitespace. To search on a docs page, add a space after the function or keyword name, and then enter your search query.

Here’s a command you could run to find JavaScript’s Array.prototype.unshift()and search on that docs page for the ‘specification’ header, where the associated ECMAScript standards for unshift are found.

unshift specification

This command from Alfred could look like:

dash unshift specification

Integrate Alfred and Dash 🤝

Today I’m testing an intergration between Alfred, the powerful alternative to Finder, and Dash, the local-documentation tool for Mac. My goal is a single command, run from anywhere on a Mac, that searches one or many sets of docs for a named function.

This tutorials showed me how to do it. TL;DR, it’s a one-click setup in Dash:

https://github.com/Kapeli/Dash-Alfred-Workflow

Once complete, I can trigger Alfred (with CMD + SPACE, or any key combo that’s not assigned elsewhere), type dash List.reverse, hit enter, and Alfred loads all the List.reverse docs I’ve downloaded in Dash.

How to expose entire Swift class to Objective-C

Use the @objcMembers annotation in your Swift class. When working on a project that is migrating from Objective-C to Swift you will most likely be sharing all Swift functions with Objective-C, but that could start to look ugly:

class MyClass: NSObject {
  @objc func fancy() -> String {
    return "fancy"
  }
  
  @objc func tooFancy() -> String {
    return "🤵"
  }
}

But if everything needs to be available to Objective-C, we simply do:

@objcMembers
class MyClass: NSObject {
  func fancy() -> String {
    return "fancy"
  }
  
  func tooFancy() -> String {
    return "🤵"
  }
}

How to remove NotificationCenter observer in Swift

Use the method deinit. In Objective-C classes I would always remove NSNotificationCenter observers in the -dealloc method, but a Swift class doesn’t have a -dealloc method. Instead, Swift has a deinit method.

Here is an example of Objective-C:

@implementation MyClass
  - (void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
  }
@end

And the equivilant in Swift:

class MyClass {
  deinit {
    NotificationCenter.default.removeObserver(self)
  }
}

Open iOS simulator app data directory

If you need to quickly open an app’s document directory on the iOS Simulator, you can quickly get the path from the xcrun CLI.

xcrun simctl get_app_container booted ${bundle_id} data

Here’s some ruby you can throw into a Rakefile of your iOS app 😉

# Rakefile
desc "Open the simulator document directory"
task :docs do
  bundle_id = File.read("MyAppName/MyAppName.xcodeproj/project.pbxproj")
    .scan(/PRODUCT_BUNDLE_IDENTIFIER = "(.*)"/)
    .flatten.first

  app_directory = `xcrun simctl get_app_container booted #{bundle_id} data`

  puts "Opening simulator directory: #{app_directory}"
  `open #{app_directory}`
end

Friendly Zoom Personal Meeting URL ➡

If you have a Zoom account, you have a Personal Meeting URL— a permanent video conferencing room tied to your account. It looks like this:

https://zoom.us/j/5551112342

When another person with Zoom installed visits this link in a browser, their Zoom client joins a call in your room.

A pro move is to redirect a subdomain like this to your room:

chat.tomcruise.com

Now you have a memorable link you can share with others.

Improve Your Stack Overflow Feed ⬆

I like answering questions on Stack Overflow. It helps me stay aware of what people are struggling with in a particular language or framework. To do this well, I manage my tags. Here’s a screenshot of some of the tags I’m watching (subjects I care about and can contribute answers to) and ignoring (the rest).

image

With these settings, my question feed is mostly signal rather than noise.

If you visit Stack Overflow often and haven’t signed up for an account, I recommend it.

Open Newest Email with Gmail

Part of my Gmail workflow includes hotkeys. I’d recommend them to anyone who wants to use their email more efficiently.

My current favorite command is gio, or gi (show inbox), combined with o (open focused message), which defaults to the newest message. gio lets me open my newest email without a mouse, faster than you can say ‘unsubscribe’.

Combine this with Vim motions (j and k) and you’re off to the races. 🏁

Access Unsupported Resolutions With RDM On Mac

If you visit the Display Settings for your Mac, you’ll find that you only have a handful of screen resolution options. For standard use, you’ll get by with these. If you need a specific, unsupported resolution you’ll need help from a 3rd party tool. There are many options out there. RDM is a free and open-source option.

Once you have it installed and have given it Accessibility permissions, open the menu from your top toolbar and select the resolution you are looking for.

I use RDM to adjust my screen resolution to 1280x720 for optimal screencasting.

🔍 Using NSArray with CONTAINS NSPredicates

NSPredicate’s predicateWithFormat method takes a va_list of arguments, so it’s not possible to pass an array to your format string. But, the same result can be achieved by combining multiple NSPredicates together using an NSCompoundPredicate:

Given a space-separated array of search words:

NSArray<NSString*> *words = [@"my search terms" componentsSeparatedByString:@" "];

You can combine them by first creating multiple predicates:

NSMutableArray<NSPredicate *> *predicates = [NSMutableArray new];
for (NSString *word in words) {
  NSPredicate *predicate = [NSPredicate predicateWithFormat:@"attribute CONTAINS[cd] %@", word];
  [predicates addObject:predicate];
}

And finally create one NSPredicate via NSCompoundPredicate

NSPredicate *finalPredicate =
        [NSCompoundPredicate andPredicateWithSubpredicates:predicates];

Copy Some Data From The Chrome Console

Sometimes you have some data that you are playing around with in the console, something you logged from an API response. You then want to share it, so you try to copy the whole thing into your system copy buffer. There are a couple hacky ways of doing this, but Chrome supports a really smooth way.

Use the copy function.

characters
> (8) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]
copy(characters[1])

My system copy buffer now contains the entire object that makes up the second entry in that list. I can then paste it into Slack or wherever.

source

Open Slack's Keyboard Shortcuts Reference Panel

Slack has a ton of keyboard shortcuts, but you might only be familiar with some of the more obvious ones. When I started using Slack, I quickly discovered that Cmd+} and Cmd+{ allow you to navigate forward and backward through your different Slack workspaces.

But there is a whole world of Slack keyboard shortcuts that I didn’t know about. By hitting Cmd+/ a Keyboard Shortcuts reference panel will be toggled open. This lists all of the keyboard shortcuts you didn’t know you needed.

Gesture To View All Windows Of Current Mac App

I use a Mac as my primary development machine. When working on a web application, I often end up with a couple Chrome windows open and sometimes even a couple terminal windows open. I generally use the Cmd+~ key binding to toggle through them. This can occasionally get confusing though. To get the fuller picture, I can get a birds-eye view of all windows for the current app using a track pad gesture.

Swiping down with three fingers on the track pad will provide a zoomed out view of all windows. Click on the window you care about to view that or swipe back up with three fingers to dismiss it.

source

Enable Keyboard Shortcuts In Gmail

In these modern times of asynchronous communication and paperless receipts, a person’s email inbox can get mighty full. Keeping that influx of emails at bay is a challenge. If you’d like to start unburying yourself and get on the path to inbox zero — Gmail’s keyboard shortcuts can help.

Keyboard shortcuts are not enabled by default, so you’ll need to turn them on in settings. Click the gear icon, select Settings and then scroll down under the General tab until you find the Keyboard shortcuts section. Select the Keyboard shortcuts on radio button and then Save changes.

You’ll now have access to a variety of shortcuts, such as using the j and k keys to move up and down the list of emails in your inbox. Find the one you want and hit o to open it up.

Keep exploring — there is a whole world of keyboard shortcuts out there.

h/t Jake Worth

Gmail 'o'

In my quest to learn all the Gmail hotkeys, today I learned ‘o’.

‘o’ opens the focused email in your inbox. Combine this with ‘gi’ (go to inbox) and Vim-style JK (down/up throught the inbox list), and you’re cruising. 🏁

Hotkeys must be enabled in your settings.

Change the Mac Screenshots Dir

If you like a clean virtual desktop, then placing all screenshots on the Desktop can be incredibly messy.

To change the desktop location:

> defaults write com.apple.screencapture location ~/Desktop/Screenshots

Let’s say you configured this to a weird directoy and you want remember where you are saving screenshots, you can read that configuration.

> defaults read com.apple.screencapture location
~/Desktop/Screenshots

ProxyJump: simplest way to ssh with a jump host

Ever need to jump your ssh through an intermediate host? You may be familiar with using netcat like this in your ~/.ssh/config:

Host jumpy
  ProxyCommand ssh -q jump-host nc destination-host %p

ProxyCommand runs on our local machine. The command must open a tcp connection that ssh may then use for the session. Here we shell into our jump-host, connecting the file descriptors to nc, which will forward all data to destination-host on %p, the port you provided to -p on the cli.

Clear as mud, no?

Another slightly more readable way to achieve this is with -W

Host jumpy
  ProxyCommand ssh -W destination-host jump-host

This works the same way as the nc version, but now we are using ssh’s internal implementation of nc. So one less dependency on the jump host.

But behold, the most legit and legible version of jumping hosts:

Host jumpy
  Hostname destination-host
  ProxyJump jump-host

So same thing, but now the words say what it does.

When you get lost remember that .ssh/config has it’s own man page:

$ man ssh_config

Thanks Dillon!

Duplicate The Current Tab In Chrome

Sometimes when viewing a page in Chrome, you realize you want to keep that page open but also go back to the previous page to view something else. An easy way of achieving this is to duplicate the current tab and then go back.

To duplicate the current tab hit Cmd+Enter while the focus is on the URL bar.

If the URL bar is not in focus, then first hit Cmd+L to focus followed by Cmd+Enter.

Start Zoom on Mute 📣

We’ve been using Zoom for a while now; it’s an excellent video conferencing tool.

One setting I recommend enabling is ‘Always mute microphone when joining meeting’, under the ‘Audio’ settings. I’ve been using it for a week and love it. Pausing work in an open office to join a conference call can be a messy affair, and this setting helps me control how I enter the conversation (silently).

Shell parameter expansion

Shells can perform variable expansion, this is really useful for default argument variables in shell functions.

Here is a simple example of assigning a variable from an argument or defaulting to running a different shell command:

clog() {
  log_date=${1-`date +%Y-%m-%d`}
  git log --after="$log_date 00:00" --before="$log_date 23:59"
}

This allows me to write

clog to default to today’s date or

clog 2018-10-02 to look at the logs from yesterday

The date in the example clog 2018-10-02 would come through as $1 in the function, so ${1-`date`} means run this shell command if there is no $1.

*references:

https://www.tldp.org/LDP/abs/html/parameter-substitution.html#USAGEMESSAGE

Select a Square With Mac Preview

Lately I’ve been taking screenshots of code and my terminal. They seem to look the best when they’re square; that shape translates better to a variety of project management tools and social media platforms.

Mac Preview lets you select part of an image down to the pixel for cropping, and I have found selecting a perfect square very difficult. The solution? Select with SHIFT + click to force a square-shaped selection. ⌘ + K to crop.

🔲

Enable Breadcrumbs For VS Code 1.26 Release

The latest release of Code (Version 1.26) brings about a lot of exciting new features — including file breadcrumbs at the top of each file editor view.

Breadcrumbs feature in action

By default this feature is not enabled. You can enable it from User Settings (Cmd+Shift+P, ‘User Settings’). From the User Settings view, you can search for breadcrumbs and you’ll see the following item:

  "breadcrumbs.enabled": false,

Use the pencil to override it to true and you’ll have that trail of breadcrumbs waiting for you.

Two ways to access emojis in Windows 10

Include an emoji via keyboard shortcut while typing in Windows 10 by using the Windows key together with the period key. Windows key + semicolon is also a valid shortcut.

No keyboard handy? In the right-hand part of the taskbar, there is a small keyboard icon. If that is not visible, you can enable it by right-clicking on the taskbar.

Clicking this taskbar icon enables the touch keyboard, which includes a smiley key that takes you to to the emoji list.

Now, you can express yourself. 🤠

Add The VSCode CLI To Your Path

Visual Studio Code has a command line tool that can do a bunch of things. Perhaps the most common is opening up the current directory from the command line.

First, you need to add code to your path. This can be done from within Code itself.

Hit Cmd+Shift+p to pop open the command palette. Then start typing Shell Command ... until the Shell Command: Install "code" command in shell PATH option appears. Select this and Code will add code to your path.

Try code . to open the current directory or run code --help for more details on what’s available.

Log Into Windows 10 Without A Keyboard

Sometimes you might need to log into a Windows machine without a keyboard. A damaged keyboard, non-functioning ports for connecting an external keyboard, or a faulty keyboard driver could put you in this predicament.

Windows 10 includes an accessibility menu called ‘Ease of Access’, located in the lower righthand corner of the screen. This menu includes an on-screen keyboard. Use it to log in when your keyboard doesn’t work.

Ease of Access