1
0
mirror of https://github.com/jbranchaud/til synced 2026-01-15 21:18:02 +00:00

Compare commits

...

221 Commits

Author SHA1 Message Date
copilot-swe-agent[bot]
c58bfbb37f Reorder commands: commit before pull --rebase
Co-authored-by: jbranchaud <694063+jbranchaud@users.noreply.github.com>
2026-01-01 00:18:25 +00:00
copilot-swe-agent[bot]
9b5af6a535 Simplify pull command to use configured upstream
Co-authored-by: jbranchaud <694063+jbranchaud@users.noreply.github.com>
2026-01-01 00:17:23 +00:00
copilot-swe-agent[bot]
62d194f492 Add git pull --rebase to notes:push task
Co-authored-by: jbranchaud <694063+jbranchaud@users.noreply.github.com>
2026-01-01 00:16:23 +00:00
copilot-swe-agent[bot]
7a7a0faf94 Initial plan 2026-01-01 00:14:07 +00:00
jbranchaud
d980514bff Add Create Interactive Picker For Set Of Subtasks as a Taskfile TIL 2025-12-31 12:33:50 -07:00
jbranchaud
db26fc97c6 Add Set Up Forwarding Prefix For Nested Session as a tmux TIL 2025-12-31 12:10:52 -07:00
jbranchaud
8094448877 Add Join URI Path Parts as a Ruby TIL 2025-12-30 10:39:03 -07:00
jbranchaud
883b3e6ee6 Add Run Dev Processes With Overmind Instead Of Foreman as a Rails TIL 2025-12-28 10:21:35 -06:00
jbranchaud
57c4954d6f Add Regenerate Lock File With Newer Bundler as a Ruby TIL 2025-12-26 11:33:07 -06:00
jbranchaud
86a7815a9f Add Specify Default Team And App For Project as a Heroku TIL 2025-12-22 20:46:45 -06:00
jbranchaud
676038e992 Add Create A Module Of Utility Functions as a Ruby TIL 2025-12-17 16:54:43 -06:00
jbranchaud
01fd503a92 Add Run Rails Console With Remote Dokku App as a Rails TIL 2025-12-15 22:27:47 -06:00
jbranchaud
8b718aee4f Add Describe Current Changes And Create New Change as a jj TIL 2025-12-10 11:34:13 -06:00
jbranchaud
88f49de7f3 Add Reference The Full Match In The Replacement as a Sed TIL 2025-12-01 14:07:25 -06:00
jbranchaud
9f9fce7835 Add Make Structs Easier To Use With Keyword Initialization as a Ruby TIL 2025-12-01 06:35:43 -06:00
jbranchaud
65a4d0ef3d Add Rename A Bunch Of Files By Constructing mv Commands as a Unix TIL 2025-11-30 20:10:59 -06:00
jbranchaud
6c8a5eb36d Add new newsletter URL 2025-11-29 15:10:43 -06:00
jbranchaud
fed722d7fe Add Access Your GitHub Profile Photo as a GitHub TIL 2025-11-29 14:40:34 -06:00
jbranchaud
fbebc3e5ee Add Install And Require Gems Inline Without Gemfile as a Ruby TIL 2025-11-28 23:24:00 -06:00
jbranchaud
83d55c420e Add Use .ruby Extension For Template File as a Rails TIL 2025-11-27 10:29:56 -06:00
jbranchaud
8dbbfe0eda Add Create Mock Class That Can Be Overridden as a Ruby TIL 2025-11-25 22:18:00 -06:00
jbranchaud
c38d9f090e Add Monitor Usage Limits From CLI as a Claude Code TIL 2025-11-22 08:43:26 -06:00
jbranchaud
bae3527baf Add Determine ipv4 And ipv6 Public IP Addresses as a Unix TIL 2025-11-21 16:43:08 -06:00
jbranchaud
53a0b88eff Add Get Idea Of What Is In A JSON Column as a MySQL TIL 2025-11-20 09:06:08 -06:00
jbranchaud
665c8f994f Add List All Git Aliases From gitconfig as a Git TIL 2025-11-19 14:39:41 -06:00
jbranchaud
5f11b1665b Remove dprint config to never text wrap
This was causing multi-line sequences of text in TIL markdown files to be
unwrapped into one long line.
2025-11-18 13:20:58 -06:00
jbranchaud
ce5ff038c0 Add Generate A Sequence Of Numbered Items as a Unix TIL 2025-11-18 13:20:49 -06:00
jbranchaud
486a6ef5a9 Add Open Current Prompt In Default Editor as a Claude Code TIL 2025-11-18 12:54:50 -06:00
jbranchaud
c1ce559452 Add Add A Bunch Of CLI Utilities With corutils as a Mac TIL 2025-11-16 22:21:45 -06:00
jbranchaud
07c4aa86b7 Add Squash Changes Into Parent Commit Interactively as a jj TIL 2025-11-16 17:31:42 -06:00
jbranchaud
a0c2a29a96 Add See What Databases You Have Access To as a Planetscale TIL 2025-11-16 10:34:44 -06:00
jbranchaud
45b269abf1 Add Launch Some Confetti as a Mac TIL 2025-11-14 18:52:45 -06:00
jbranchaud
44dc6f2b1f Add Install Go Packages In Brewfile as a Brew TIL 2025-11-14 18:19:43 -06:00
jbranchaud
821a7e5c67 Add Do Project Time Tracking From The CLI as a Workflow TIL 2025-11-14 00:32:13 -06:00
jbranchaud
c0f20267bb Add Shorten SSH Commands With Aliases as a Unix TIL 2025-11-12 15:00:19 -06:00
jbranchaud
50deb6175f Add Detect How Long A User Has Been Idle as a Mac TIL 2025-11-11 17:13:36 -06:00
jbranchaud
d1f41884ce Add Set Default Tasks For Rake To Run as a Ruby TIL 2025-11-10 18:06:12 -06:00
jbranchaud
91149fe7cc Add Show Summary Stats For Current Branch as a Git TIL 2025-11-10 17:25:24 -06:00
jbranchaud
e2eb31a4a9 Add Reference Hash Key With Safe Navigation as a Ruby TIL 2025-11-09 17:12:09 -05:00
jbranchaud
113b7b2dfe Add Prevent Sleep With The Caffeinate Command as a Mac TIL 2025-11-09 13:50:03 -05:00
jbranchaud
16074c021f Add Convert JSON Field To Hash With Indifferent Access as a Rails TIL 2025-11-08 08:55:41 -05:00
jbranchaud
9e76753540 Add Open File On Remote Like GitHub as a VSCode TIL 2025-11-03 14:19:14 -05:00
jbranchaud
eb4dea611e Add Inspect Assertions Preventing Sleep as a Mac TIL 2025-11-02 15:21:31 -06:00
jbranchaud
6ef998b024 Add Check If A File Is Under Version Control as a Git TIL 2025-11-02 11:01:30 -06:00
jbranchaud
6e066ec72a Add Target Another Repo When Creating A PR as a GitHub TIL 2025-11-02 08:18:41 -06:00
jbranchaud
060ce8262d Add Set Up A Project-Local Cluster With Postgres.app as a Postgres TIL 2025-11-01 08:41:56 -05:00
jbranchaud
96fd138837 Add Exclude A Specific File From fd Results as a Unix TIL 2025-10-31 16:09:44 -05:00
jbranchaud
a51d716e45 Add Reword A Commit Message With Fugitive as a Vim TIL 2025-10-29 22:26:37 -05:00
jbranchaud
59de2fef0d Add Add Bindings To Split Panes To Current Directory as a tmux TIL 2025-10-29 21:38:06 -05:00
jbranchaud
fdd2461b75 Add Check If A File Has Changed In A Script as a Git TIL 2025-10-28 12:25:43 -05:00
jbranchaud
e8c2e01d6f Add better status check for notes:push 2025-10-28 08:29:15 -05:00
jbranchaud
ed9cedc870 Add Run A Task If It Meets Criteria as a Taskfile TIL 2025-10-28 08:26:39 -05:00
jbranchaud
da585ec5a4 Add Allow Cursor To Be Launched From CLI as a Cursor TIL 2025-10-27 21:37:59 -05:00
jbranchaud
35d1a81ea7 Move recent TIL to new GitHub category 2025-10-27 17:08:55 -05:00
jbranchaud
d69fefe9f0 Use status instead of precondition to avoid error 1 2025-10-27 17:07:21 -05:00
jbranchaud
1cc612294e Run notes:push steps only if there are changes 2025-10-27 16:45:03 -05:00
jbranchaud
d79264395b Add Open A PR To An Unforked Repo as a GitHub TIL 2025-10-27 15:14:00 -05:00
jbranchaud
2d5abd9cbf Revert to excluding entire README formatting
The `unorderedListMarker` setting was hallucinated.
2025-10-26 18:20:47 -05:00
jbranchaud
2efaf27066 Add Tell gh What The Default Repo Is as a Git TIL 2025-10-26 17:58:42 -05:00
jbranchaud
6b4b2c588c Rework notes task to make edit the primary one
What was 'edit' has been renamed to 'open'. And 'edit' is now what was
not so clearly named 'save'.
2025-10-26 17:14:51 -05:00
jbranchaud
e473fa781d Move notes higher up, it is most common command 2025-10-26 17:09:51 -05:00
jbranchaud
5ce5eccb0a Add Jump Between Changes In Current File as a Neovim TIL 2025-10-26 16:52:24 -05:00
jbranchaud
db4961a8eb Don't error if you escape from fzf 2025-10-25 13:40:17 -05:00
jbranchaud
ff227a39ed Turn of only dprint's unordered list formatting 2025-10-25 12:51:25 -05:00
jbranchaud
0d3975eb9c Disable dprint for README for bullet formatting 2025-10-25 12:49:33 -05:00
jbranchaud
d171c3784b Get rid of the help task, not needed now 2025-10-25 11:51:27 -05:00
jbranchaud
e6d00a94f3 Add an interactive picker for notes tasks 2025-10-25 11:50:22 -05:00
jbranchaud
0e934d8dd3 Add a default task to list all tasks 2025-10-25 10:05:38 -05:00
jbranchaud
c30b17dd68 Add a taskfile for managing notes submodule 2025-10-25 09:59:34 -05:00
jbranchaud
757e163c2e Ignore all changes to the notes submodule 2025-10-25 00:57:38 -05:00
jbranchaud
cf037f13f7 Tell the submodule to use the main branch 2025-10-25 00:50:16 -05:00
jbranchaud
08fb235e81 Add submodule for including private notes file 2025-10-25 00:37:04 -05:00
jbranchaud
95dc00d748 Add Get The Names Of The Month as a Ruby TIL 2025-10-24 15:18:40 -05:00
jbranchaud
ece12aac76 Add Clean Up Your Brew Installations as a Brew TIL 2025-10-23 14:23:11 -05:00
jbranchaud
9a6a40bdd6 Add Capture Screenshot To Clipboard From CLI as a Mac TIL 2025-10-22 15:40:50 -05:00
Jake Worth
4b4bd2350f Fix typo 2025-10-19 22:44:16 -05:00
jbranchaud
5924edf4c0 Add Set Up GPG Signing Key as a Git commit 2025-10-19 15:06:09 -05:00
jbranchaud
5eb21b3aa2 Add Transform Text To Lowercase as a Unix TIL 2025-10-17 21:49:38 -05:00
jbranchaud
5b3f1536fd Add Format Specific html.erb Template Files as a Rails TIL 2025-10-16 08:55:51 -05:00
jbranchaud
ec0e84664f Add Prevent Mailer Previews From Cluttering Database as a Rails TIL 2025-10-06 08:52:25 -05:00
jbranchaud
3912276599 Add Allow Number Input To Accept Decimal Values as an HTML TIL 2025-10-04 10:24:36 -05:00
jbranchaud
d166ffac0b Add Scope Records To A Lower Or Upper Bound as a Rails TIL 2025-10-03 19:59:00 -05:00
jbranchaud
e8b953ba6d Add Disable And Enable A Button as a Tailwind TIL 2025-09-29 18:54:05 -05:00
jbranchaud
8613c21f41 Add Avoid Double Negation With Minitest Refute as a Ruby TIL 2025-09-16 09:33:48 -05:00
jbranchaud
2b5df03981 Fix ordering of two TILs in README 2025-09-16 09:32:46 -05:00
jbranchaud
aef15d53b0 Add Parameterize A String With Underscores as a Rails TIL 2025-09-12 12:05:26 -05:00
jbranchaud
0c31fb6363 Add Clear Entries From Git Stash as a Git TIL 2025-08-05 09:10:20 -05:00
jbranchaud
cb94142042 Add Decompose Unicode Character With Diacritic Mark as a Ruby TIL 2025-07-21 17:38:41 -05:00
jbranchaud
ae2974e3b8 Add Authorize A cURL Request as a Unix TIL 2025-07-02 12:25:32 -05:00
jbranchaud
0ed4d84bc6 Add Get Specific Values From Hashes And Arrays as a Ruby TIL 2025-07-02 10:09:48 -05:00
jbranchaud
3b7e3258fe Add View A Nicely-Formatted CSV In Terminal as a Workflow TIL 2025-06-27 16:13:28 -05:00
jbranchaud
d00796b054 Add Manage Timestamps With Upsert as a Rails TIL 2025-06-26 09:21:17 -05:00
jbranchaud
8fecb0e863 Add References Target Primary Key By Default as a Postgres TIL 2025-06-19 09:59:12 -05:00
jbranchaud
14942c20d7 Add Provide Fake Form Helper To Controllers as a Rails TIL 2025-06-16 10:28:18 -05:00
jbranchaud
e901ae3b77 Add Restore File From One Branch To The Current as a Git TIL 2025-06-11 09:08:59 -05:00
jbranchaud
a4fee08596 Add a couple links to the About section of README 2025-06-09 09:44:40 -05:00
jbranchaud
6e518763c7 Add Check The Size Of Databases In A Cluster as a Postgres TIL 2025-05-06 21:21:57 -05:00
jbranchaud
bb40353512 Add Customize Template For New Schema Migration as a Rails TIL 2025-05-03 21:15:07 -05:00
jbranchaud
917f9e516e Add Cherry Pick Multiple Commits At Once as a git TIL 2025-05-02 23:14:16 -05:00
jbranchaud
d8dfcce0fc Add Format DateTime With Builtin Formats as a Rails TIL 2025-04-30 23:18:32 -05:00
jbranchaud
0d173ccaaf Add Interpret Cron Schedule From The CLI as a Unix TIL 2025-04-24 15:46:19 -05:00
jbranchaud
8dd9f86b80 Add Highlight Small Change On Single Line as a Git TIL 2025-04-17 18:19:12 -05:00
jbranchaud
2bb8af2880 Add Vimium course under other learning resources 2025-04-17 17:22:17 -05:00
jbranchaud
e16c2525be Add Run nvim With Factory Defaults as a Neovim TIL 2025-04-12 16:32:22 -05:00
jbranchaud
a55fff68e1 Add Exclude A Directory During A Command as a Git TIL 2025-04-12 16:03:06 -05:00
jbranchaud
162a7ceea3 Add Format A List Of Items By Locale as a JavaScript TIL 2025-04-11 17:47:33 -05:00
jbranchaud
f578727349 Add Make Neovim The Default Way To View Man Pages as a Unix TIL 2025-04-09 21:25:17 -05:00
jbranchaud
4ba53dca7d Add Create And Execute SQL Statements With \gexec as a Postgres TIL 2025-04-07 17:52:13 -05:00
jbranchaud
571f465fe6 Fix some typos in an old git TIL 2025-04-07 17:18:05 -05:00
jbranchaud
a547b9cee2 Add Create A Filename With The Current Date as a Unix TIL 2025-04-02 09:26:38 -05:00
jbranchaud
99ce5aee7b Add Bypass On-Save Tooling When Writing File as a Vim TIL 2025-04-01 10:56:25 -05:00
jbranchaud
60b6aa40ad Add Open Current Tab In New Window With Vimium as a Chrome TIL 2025-03-31 10:18:13 -05:00
jbranchaud
f97634a61e Add Have Script ShellCheck Itself When Executing as a Unix TIL 2025-03-29 09:20:39 -05:00
jbranchaud
34ba60d313 Add List RDS Snapshots With Matching Identifier Prefix as an AWS TIL 2025-03-28 11:25:31 -05:00
jbranchaud
3a178e901e Add Filter ActiveModel Validation Errors as a Rails TIL 2025-03-27 10:41:35 -05:00
jbranchaud
db07125ba9 Add Output CLI Results In Different Formats as an AWS TIL 2025-03-25 10:53:22 -05:00
jbranchaud
b6cf4ba0ad Add Search Tabs With The Vimium Vomnibar as a Chrome TIL 2025-03-24 20:22:52 -05:00
jbranchaud
e4d695e465 Add Show Reconstructed Constraints For A Table as a Postgres TIL 2025-03-22 12:02:03 -05:00
jbranchaud
5c9a3888fd Add Find And Copy A Value From Large JSON Output as a Unix TIL 2025-03-21 10:22:50 -05:00
jbranchaud
22541826d6 Add Go To Beginning And End Of Line as a Vim TIL 2025-03-19 11:50:10 -05:00
jbranchaud
b39ee94c90 Add Run SQL Script Against Postgres Container as a Docker TIL 2025-03-19 09:50:23 -05:00
jbranchaud
efad7da916 Add Turn Off Output Pager For A Command as an AWS TIL 2025-03-18 18:34:11 -05:00
jbranchaud
ca3327bda3 Add Show The Bundler Location Of An Installed Gem as a Ruby TIL 2025-03-18 11:05:38 -05:00
jbranchaud
595ac85f17 Add Fetch Data From An Endpoint In SQL as a Postgres TIL 2025-03-17 17:31:32 -05:00
jbranchaud
92d732c769 Add Check Postgres Version Running In Docker Container as a Docker TIL 2025-03-15 14:03:55 -05:00
jbranchaud
d6ebe52523 Add Run A Command With Specific Tool Version as a Mise TIL 2025-03-14 16:34:39 -05:00
jbranchaud
93398ab950 Add Add Color To The IRB Console Prompt as a Rails TIL 2025-03-13 10:31:32 -05:00
jbranchaud
b1b2aa8982 Add Break Debugger On First Line Of Program as a Python TIL 2025-03-12 10:35:08 -05:00
jbranchaud
6cbf1cb974 Add Download A Google Doc As Specific Format as an Internet TIL 2025-03-11 17:03:40 -05:00
jbranchaud
79faae1047 Add Create Umbrella Task For All Test Tasks as a Mise TIL 2025-03-10 18:07:38 -05:00
jbranchaud
1316eb70ec Add Grab The RSS Feed For A Substack Blog as an Internet TIL 2025-03-09 19:10:33 -05:00
jbranchaud
ddf1c51fd9 Add Filter ActiveStorage Blobs To Only Images as a Rails TIL 2025-03-08 16:18:44 -06:00
jbranchaud
60020d6e0e Add Preserve Color Output For Task Command as a Mise TIL 2025-03-08 16:07:39 -06:00
jbranchaud
ef9f88f3c8 Add Prevent Invisible Elements From Being Clicked as a CSS TIL 2025-03-07 21:30:52 -06:00
jbranchaud
c8445c45a9 Add Read Existing Dot Env File Into Env Vars as a Mise TIL 2025-03-05 13:19:08 -06:00
jbranchaud
497b0ff3b7 Add Files With Local Changes Cannot Be Removed as a Git TIL 2025-03-04 18:05:58 -06:00
jbranchaud
64df6d16d7 Add Find All Tool Version Files Containing Postgres as a Unix TIL 2025-03-04 17:41:03 -06:00
jbranchaud
7dac057246 Add List The Files Being Loaded By Mise as a Mise TIL 2025-03-04 09:24:27 -06:00
jbranchaud
8961c67026 Add Create Todo Items In Logseq as a Workflow TIL 2025-03-03 17:06:58 -06:00
jbranchaud
4ff24a7336 Add Restart Puma Server By Touching Restart File as a Rails TIL 2025-03-01 09:48:48 -06:00
jbranchaud
2916fbc3b5 Add Create And Jump Into A Directory as a Zsh TIL 2025-02-28 10:39:23 -06:00
jbranchaud
e3fc10edd8 Fix alphabetical ordering of Rails TILs 2025-02-26 16:53:08 -06:00
jbranchaud
4fe0817b2d Add Buy Me A Coffee Link to README 2025-02-26 16:52:32 -06:00
jbranchaud
fc74264040 Add Adjust The Production Log Level as a Rails TIL 2025-02-26 16:52:13 -06:00
jbranchaud
2b38e1caf8 Add SSH Into An ECS Container as an AWS TIL 2025-02-25 12:12:52 -06:00
jbranchaud
db6d18f086 Add Enforce Locals Passed To A Partial as a Rails TIL 2025-02-24 19:15:52 -06:00
jbranchaud
84548b7a7f Add List The PID And Name Of Current Shell Process as a Unix TIL 2025-02-23 10:12:52 -06:00
jbranchaud
f9b966a0f1 Add Use Specific AWS Profile With CLI as an AWS TIL 2025-02-23 09:57:30 -06:00
jbranchaud
871d555e95 Add Filter Blur Requires Expensive Calculation as a CSS TIL 2025-02-21 15:29:14 -06:00
jbranchaud
cea3bc05b5 Add Fix Previous Command With fc as a Unix TIL 2025-02-20 17:42:32 -06:00
jbranchaud
ee31f5b70d Add Find And Follow Server Logs as an AWS TIL 2025-02-19 09:00:35 -06:00
jbranchaud
5b6a88b327 Remove the amplify TOC item, no longer exists 2025-02-19 09:00:11 -06:00
jbranchaud
49ebb8dd78 Add A Better Way To Reload ZSH Configuration as a ZSH TIL 2025-02-18 17:06:35 -06:00
jbranchaud
6ff8f19d08 Add OpenStruct Has Bad Performance Characteristics as a Ruby TIL 2025-02-17 15:32:15 -06:00
jbranchaud
14e6635383 Add Fix Shim Path After asdf Upgrade as a Unix TIL 2025-02-17 10:31:58 -06:00
jbranchaud
0a0a509827 Link to groff in latest TIL 2025-02-17 09:52:06 -06:00
jbranchaud
bb331577ca Collapse Amplify category into the AWS category 2025-02-17 09:46:02 -06:00
jbranchaud
0e0dcbf2b4 Add AWS CLI Requires Groff Executable as an AWS TIL 2025-02-17 09:44:27 -06:00
jbranchaud
fe9b62a631 Add Prevent Containers From Running On Startup as a Docker TIL 2025-02-13 11:44:38 -06:00
jbranchaud
eb3369d296 Add Limit Protocols Used In A cURL Command as a Unix TIL 2025-02-10 17:10:15 -06:00
jbranchaud
6f47e2f057 Add Uninstall LogiTech G Hub From Mac as a Mac TIL 2025-02-10 15:24:15 -06:00
jbranchaud
409201611f Add Get Word Count For All Files In Git Repo as a Unix TIL 2025-02-08 18:07:54 -06:00
jbranchaud
77cc07a908 Add Reference Commits Earlier Than Reflog Remembers as a Git TIL 2025-02-07 22:09:28 -06:00
jbranchaud
633c1fa0a5 Add Count The Number Of Words On A Webpage as a Unix TIL 2025-02-05 11:28:06 -06:00
jbranchaud
96c394c198 Add Extract Capture Group Matches With String Slices as a Ruby TIL 2025-02-03 15:29:56 -06:00
jbranchaud
0251157dc4 Add Determine The Configured Primary Key Type as a Rails TIL 2025-02-02 21:50:16 -06:00
jbranchaud
97c8701a5a Add Use Labels To Block PR Merge as a GitHub Actions PR 2025-02-01 14:10:25 -06:00
jbranchaud
1fd64e478a Clarify some things in the latest TIL 2025-01-31 14:34:53 -06:00
jbranchaud
8ea123369b Add Trim Leading And Trailing Space From String as a Postgres TIL 2025-01-31 14:23:34 -06:00
jbranchaud
43c6e08b34 Add Add A Generated Column To A PostgreSQL Table as a Rails TIL 2025-01-30 23:10:23 -06:00
jbranchaud
61fc021f52 Add Unable To Infer Data Type In Production as a Postgres TIL 2025-01-28 18:40:09 -06:00
jbranchaud
46ad33df7e Add Set Meta Tags In ERB Views as a Rails TIL 2025-01-28 18:30:12 -06:00
jbranchaud
2028f6cb09 Add List All Fonts On Your Machine as a Unix TIL 2025-01-27 23:34:44 -06:00
jbranchaud
1f039a8958 Add Default Rails Deploy Script On Hatchbox as a devops TIL 2025-01-26 21:12:39 -06:00
jbranchaud
c6eefeac98 Add Count The Number Of Items In An Array as a Postgres TIL 2025-01-25 19:02:13 -06:00
jbranchaud
31a0224fb7 Add Send A PDF To Your Kindle as a Workflow TIL 2025-01-24 15:27:25 -06:00
jbranchaud
aa71ff5f8b Add Override Text Displayed By Form Label as a Rails TIL 2025-01-24 12:36:46 -06:00
jbranchaud
48278c4908 Add Set Up Domain For Hatchbox Rails App as a devops TIL 2025-01-23 11:43:37 -06:00
jbranchaud
8b3ef4872c Add Apply Basic HTML Formatting To Block Of Text as a Rails TIL 2025-01-21 15:48:40 -06:00
jbranchaud
c2184a5ecf Add Hatchbox Exports Env Vars With asdf as a Devops TIL 2025-01-21 15:36:44 -06:00
jbranchaud
e2a8e815e9 Add Inspect Configuration Of Database Connection as a Rails TIL 2025-01-20 10:06:13 -06:00
jbranchaud
c61ddcb326 Add Temporarily Hide CleanShot X Capture Previews as a Workflow TIL 2025-01-19 13:56:45 -06:00
jbranchaud
7632664200 Add Scaffold Auth Functionality With Rails 8 Generator as a Rails TIL 2025-01-15 16:54:29 -06:00
jbranchaud
872a1d2a00 Add Count Number Of Commits On A Branch as a git TIL 2025-01-14 17:02:19 -06:00
jbranchaud
d52a126767 Add Pop Videos Out As Picture-in-Picture as a Workflow TIL 2025-01-12 11:40:29 -06:00
jbranchaud
d9080cc583 Add List All Files Added During Span Of Time as a Git TIL 2025-01-11 13:58:07 -06:00
jbranchaud
654c65c8f6 Add missing README changes for latest TIL 2025-01-11 13:57:32 -06:00
jbranchaud
138cab4fdc Add Control Media With Drop Keyboard as a Workflow TIL 2025-01-10 16:16:01 -06:00
jbranchaud
5592d4266d Add Use A Different Font With iTerm2 as a Mac TIL 2025-01-09 11:13:17 -06:00
jbranchaud
daf448c1a5 Add Rebuild Tailwind Bundle For Dev Server as a Rails TIL 2025-01-08 19:39:41 -06:00
jbranchaud
aaddc35fcd Add Disclose Additional Details as an HTML TIL 2025-01-07 13:31:31 -06:00
jbranchaud
b575534d4e Add Difference Between Slice And Pointer To Slice as a Go TIL 2025-01-06 16:43:30 -06:00
jbranchaud
ae3ecbf72c Add Start Amphetamine Session With AppleScript as a Mac TIL 2025-01-05 19:03:26 -06:00
jbranchaud
1cf67b8f1a Add Configure Max String Print Length For Delve as a Go TIL 2025-01-04 13:07:13 -06:00
jbranchaud
f9c0a566eb Add See Where asdf Gets Current Tool Version as a Unix TIL 2025-01-03 12:11:02 -06:00
jbranchaud
527038ca23 Fix TIL count, it was off by 1 2025-01-02 13:58:26 -06:00
jbranchaud
b972673008 Add Simon Willison's TIL to list of other TILs 2025-01-02 13:54:50 -06:00
jbranchaud
cc31aae25a Update copyright date to 2025, time flies 2025-01-02 13:52:57 -06:00
jbranchaud
26f30c3225 Update README with a few learning resource links 2025-01-02 13:52:24 -06:00
jbranchaud
e14da2f207 Add Basic Delve Debugging Session as a Go TIL 2025-01-02 13:45:16 -06:00
jbranchaud
b7d4a62ecb Add Refer To Implicit Block Argument With It as a Ruby TIL 2025-01-01 12:16:53 -06:00
jbranchaud
1ad41b9776 Add Connect To A SQLite Database as a Go TIL 2024-12-31 10:48:01 -06:00
jbranchaud
11716a8fb5 Add Install Latest Version Of Ruby With asdf as a Ruby TIL 2024-12-30 19:20:33 -07:00
jbranchaud
5e19d53382 Add Pass A Struct To A Function as a Go TIL 2024-12-29 10:26:55 -07:00
jbranchaud
c8aa6ee506 Add Break Justfile Into Separate Hidden Steps as a Workflow TIL 2024-12-28 09:20:00 -07:00
jbranchaud
9c0c9222f9 Add Create A Slice From An Array as a Go TIL 2024-12-26 09:47:12 -07:00
jbranchaud
855251e478 Add Clamp To An Endless Range as a Ruby TIL 2024-12-25 22:07:58 -07:00
jbranchaud
4e5ba0ce4c Add Write A Custom Scan Function For File IO as a Go TIL 2024-12-24 11:12:32 -06:00
jbranchaud
63a92cbc29 Add Use External Diff Tool Like Difftastic as a Git TIL 2024-12-23 15:41:11 -06:00
jbranchaud
8438025005 Add Deterministically Seed A Random Number Generator as a Go TIL 2024-12-22 15:04:31 -06:00
jbranchaud
a3be570a32 Add Show Linting Errors In Zed as a Workflow TIL 2024-12-21 19:14:48 -06:00
jbranchaud
464a2af6db Add Produce The Zero Value Of A Generic Type as a Go TIL 2024-12-20 15:19:10 -06:00
jbranchaud
8801f39df0 Add Manually Pass Two Git Files To Delta as a Unix TIL 2024-12-19 18:24:27 -06:00
jbranchaud
aeb55efc3c Add Detect If Stdin Comes From A Redirect as a Go TIL 2024-12-18 11:05:29 -06:00
jbranchaud
a92af09fea Add Explore The Database Schema as a SQLite TIL 2024-12-17 12:28:13 -06:00
jbranchaud
43e6433fd6 Add Check If Cobra Flag Was Set as a Go TIL 2024-12-17 01:08:50 -06:00
jbranchaud
88e675b9a3 Add Better Diffs With Delta as a Git TIL 2024-12-15 18:31:25 -06:00
jbranchaud
f5286c1f41 Add Format Date And Time With Time Constants as a Go TIL 2024-12-14 10:52:36 -06:00
jbranchaud
8787e43458 Add Fix Whitespace Errors Throughout Branch Commits as a Git TIL 2024-12-13 14:32:11 -06:00
jbranchaud
f658a31435 Add Redirect File To Stdin During Delve Debug as a Go TIL 2024-12-12 18:40:23 -06:00
jbranchaud
db00ec69c2 Add Highlight Extra Whitespace In Diff Output as a Git TIL 2024-12-11 18:43:08 -06:00
189 changed files with 7087 additions and 15 deletions

5
.gitmodules vendored Normal file
View File

@@ -0,0 +1,5 @@
[submodule "notes"]
path = notes
url = git@github.com:jbranchaud/til-notes-private.git
branch = main
ignore = all

238
README.md
View File

@@ -8,20 +8,30 @@ warrant a full blog post. These are things I've picked up by [Learning In
Public™](https://dev.to/jbranchaud/how-i-built-a-learning-machine-45k9) and
pairing with smart people at Hashrocket.
For a steady stream of TILs, [sign up for my newsletter](https://crafty-builder-6996.ck.page/e169c61186).
For a steady stream of TILs, [sign up for my newsletter](https://visualmode.kit.com/newsletter).
_1534 TILs and counting..._
_1715 TILs and counting..._
See some of the other learning resources I work on:
- [Get Started with Vimium](https://egghead.io/courses/get-started-with-vimium~3t5f7)
- [Ruby Operator Lookup](https://www.visualmode.dev/ruby-operators)
- [Vim Un-Alphabet](https://www.youtube.com/playlist?list=PL46-cKSxMYYCMpzXo6p0Cof8hJInYgohU)
If you've learned something here, support my efforts writing daily TILs by
[buying me a coffee](https://buymeacoffee.com/jbranchaud) 💜
---
### Categories
* [Ack](#ack)
* [Amplify](#amplify)
* [Ansible](#ansible)
* [Astro](#astro)
* [AWS](#aws)
* [Brew](#brew)
* [Chrome](#chrome)
* [Claude Code](#claude-code)
* [Clojure](#clojure)
* [CSS](#css)
* [Deno](#deno)
@@ -31,6 +41,7 @@ _1534 TILs and counting..._
* [Elixir](#elixir)
* [Gatsby](#gatsby)
* [Git](#git)
* [GitHub](#github)
* [GitHub Actions](#github-actions)
* [Go](#go)
* [GROQ](#groq)
@@ -47,6 +58,7 @@ _1534 TILs and counting..._
* [Linux](#linux)
* [LLM](#llm)
* [Mac](#mac)
* [Mise](#mise)
* [MongoDB](#mongodb)
* [MySQL](#mysql)
* [Neovim](#neovim)
@@ -72,6 +84,7 @@ _1534 TILs and counting..._
* [SQLite](#sqlite)
* [Streaming](#streaming)
* [Tailwind CSS](#tailwind-css)
* [Taskfile](#taskfile)
* [tmux](#tmux)
* [TypeScript](#typescript)
* [Unix](#unix)
@@ -93,10 +106,6 @@ _1534 TILs and counting..._
- [Case-Insensitive Search](ack/case-insensitive-search.md)
- [List Available File Types](ack/list-available-file-types.md)
### Amplify
- [Sign Up User With Email And Password](amplify/sign-up-user-with-email-and-password.md)
### Ansible
- [Loop Over A List Of Dictionaries](ansible/loop-over-a-list-of-dictionaries.md)
@@ -106,10 +115,23 @@ _1534 TILs and counting..._
- [Generate Types For A Content Collection](astro/generate-types-for-a-content-collection.md)
- [Markdown Files Are Of Type MarkdownInstance](astro/markdown-files-are-of-type-markdown-instance.md)
### AWS
- [AWS CLI Requires Groff Executable](aws/aws-cli-requires-groff-executable.md)
- [Find And Follow Server Logs](aws/find-and-follow-server-logs.md)
- [List RDS Snapshots With Matching Identifier Prefix](aws/list-rds-snapshots-with-matching-identifier-prefix.md)
- [Output CLI Results In Different Formats](aws/output-cli-results-in-different-formats.md)
- [Sign Up User With Email And Password](aws/sign-up-user-with-email-and-password.md)
- [SSH Into An ECS Container](aws/ssh-into-an-ecs-container.md)
- [Turn Off Output Pager For A Command](aws/turn-off-output-pager-for-a-command.md)
- [Use Specific AWS Profile With CLI](aws/use-specific-aws-profile-with-cli.md)
### Brew
- [Clean Up Your Brew Installations](brew/clean-up-your-brew-installations.md)
- [Configure Brew Environment Variables](brew/configure-brew-environment-variables.md)
- [Export List Of Everything Installed By Brew](brew/export-list-of-everything-installed-by-brew.md)
- [Install Go Packages In Brewfile](brew/install-go-packages-in-brewfile.md)
- [List All Services Managed By Brew](brew/list-all-services-managed-by-brew.md)
### Chrome
@@ -120,10 +142,12 @@ _1534 TILs and counting..._
- [Duplicate The Current Tab](chrome/duplicate-the-current-tab.md)
- [Easier Access To Network Throttling Controls](chrome/easier-access-to-network-throttling-controls.md)
- [Keybinding To Focus The Address Bar](chrome/keybinding-to-focus-the-address-bar.md)
- [Open Current Tab In New Window With Vimium](chrome/open-current-tab-in-new-window-with-vimium.md)
- [Pause JavaScript From The Source DevTools Panel](chrome/pause-javascript-from-the-source-devtools-panel.md)
- [Navigate The Browser History With Vimium](chrome/navigate-the-browser-history-with-vimium.md)
- [Pretty Print Tabular Data](chrome/pretty-print-tabular-data.md)
- [Reference The Selected Node](chrome/reference-the-selected-node.md)
- [Search Tabs With The Vimium Vomnibar](chrome/search-tabs-with-the-vimium-vomnibar.md)
- [Selecting DOM Elements Faster Than Ever](chrome/selecting-dom-elements-faster-than-ever.md)
- [Simulating Various Connection Speeds](chrome/simulating-various-connection-speeds.md)
- [Toggle Device Mode](chrome/toggle-device-mode.md)
@@ -131,6 +155,11 @@ _1534 TILs and counting..._
- [Trigger Commands From The Devtools Command Palette](chrome/trigger-commands-from-the-devtools-command-palette.md)
- [View Network Traffic For New Tabs](chrome/view-network-traffic-for-new-tabs.md)
### Claude Code
- [Monitor Usage Limits From CLI](claude-code/monitor-usage-limits-from-cli.md)
- [Open Current Prompt In Default Editor](claude-code/open-current-prompt-in-default-editor.md)
### Clojure
- [Aggregation Using merge-with](clojure/aggregation-using-merge-with.md)
@@ -172,16 +201,22 @@ _1534 TILs and counting..._
- [Define HSL Colors With Alpha Values](css/define-hsl-colors-with-alpha-values.md)
- [Display Responsive iframe Maintaining Aspect Ratio](css/display-responsive-iframe-maintaining-aspect-ratio.md)
- [Dry Up SCSS With Mixins](css/dry-up-scss-with-mixins.md)
- [Filter Blur Requires Expensive Calculation](css/filter-blur-requires-expensive-calculation.md)
- [Give Elements The Same Width With Flexbox](css/give-elements-the-same-width-with-flexbox.md)
- [Let Pointer Events Pass Through An Element](css/let-pointer-events-pass-through-an-element.md)
- [Lighten And Darken With CSS Brightness Filter](css/lighten-and-darken-with-css-brightness-filter.md)
- [Lighten And Darken With SCSS](css/lighten-and-darken-with-scss.md)
- [Make A Block Of Text Respect New Lines](css/make-a-block-of-text-respect-new-lines.md)
- [Parameterized SCSS Mixins](css/parameterized-scss-mixins.md)
- [Prevent Invisible Elements From Being Clicked](css/prevent-invisible-elements-from-being-clicked.md)
- [:root Has Higher Specificity Than html](css/root-has-higher-specificity-than-html.md)
- [Style A Background With A Linear Gradient](css/style-a-background-with-a-linear-gradient.md)
- [Using Maps In SCSS](css/using-maps-in-scss.md)
### Cursor
- [Allow Cursor To Be Launched From CLI](cursor/allow-cursor-to-be-launched-from-cli.md)
### Deno
- [Read In The Contents Of A File](deno/read-in-the-contents-of-a-file.md)
@@ -195,21 +230,27 @@ _1534 TILs and counting..._
- [Check The Status of All Services](devops/check-the-status-of-all-services.md)
- [Check The Syntax Of nginx Files](devops/check-the-syntax-of-nginx-files.md)
- [Connect To An RDS PostgreSQL Database](devops/connect-to-an-rds-postgresql-database.md)
- [Default Rails Deploy Script On Hatchbox](devops/default-rails-deploy-script-on-hatchbox.md)
- [Determine The IP Address Of A Domain](devops/determine-the-ip-address-of-a-domain.md)
- [Hatchbox Exports Env Vars With asdf](devops/hatchbox-exports-env-vars-with-asdf.md)
- [Path Of The Packets](devops/path-of-the-packets.md)
- [Push Non-master Branch To Heroku](devops/push-non-master-branch-to-heroku.md)
- [Reload The nginx Configuration](devops/reload-the-nginx-configuration.md)
- [Resolve The Public IP Of A URL](devops/resolve-the-public-ip-of-a-url.md)
- [Running Out Of inode Space](devops/running-out-of-inode-space.md)
- [Set Up Domain For Hatchbox Rails App](devops/set-up-domain-for-hatchbox-rails-app.md)
- [SSH Into A Docker Container](devops/ssh-into-a-docker-container.md)
- [SSL Certificates Can Cover Multiple Domains](devops/ssl-certificates-can-cover-multiple-domains.md)
- [Wipe A Heroku Postgres Database](devops/wipe-a-heroku-postgres-database.md)
### Docker
- [Check Postgres Version Running In Docker Container](docker/check-postgres-version-running-in-docker-container.md)
- [Configure Different Host And Container Ports](docker/configure-different-host-and-container-ports.md)
- [List Running Docker Containers](docker/list-running-docker-containers.md)
- [Prevent Containers From Running On Startup](docker/prevent-containers-from-running-on-startup.md)
- [Run A Basic PostgreSQL Server In Docker](docker/run-a-basic-postgresql-server-in-docker.md)
- [Run SQL Script Against Postgres Container](docker/run-sql-script-against-postgres-container.md)
### Drizzle
@@ -283,22 +324,28 @@ _1534 TILs and counting..._
- [Add Only Tracked Files From A Directory](git/add-only-tracked-files-from-a-directory.md)
- [Amend Author Of Previous Commit](git/amend-author-of-previous-commit.md)
- [Auto-Squash Those Fixup Commits](git/auto-squash-those-fixup-commits.md)
- [Better Diffs With Delta](git/better-diffs-with-delta.md)
- [Caching Credentials](git/caching-credentials.md)
- [Change The Start Point Of A Branch](git/change-the-start-point-of-a-branch.md)
- [Check How A File Is Being Ignored](git/check-how-a-file-is-being-ignored.md)
- [Check If A File Has Changed In A Script](git/check-if-a-file-has-changed-in-a-script.md)
- [Check If A File Is Under Version Control](git/check-if-a-file-is-under-version-control.md)
- [Checking Commit Ancestry](git/checking-commit-ancestry.md)
- [Checkout Old Version Of A File](git/checkout-old-version-of-a-file.md)
- [Checkout Previous Branch](git/checkout-previous-branch.md)
- [Cherry Pick A Range Of Commits](git/cherry-pick-a-range-of-commits.md)
- [Cherry Pick Multiple Commits At Once](git/cherry-pick-multiple-commits-at-once.md)
- [Clean Out All Local Branches](git/clean-out-all-local-branches.md)
- [Clean Out Working Copy With Patched Restore](git/clean-out-working-copy-with-patched-restore.md)
- [Clean Up Old Remote Tracking References](git/clean-up-old-remote-tracking-references.md)
- [Clear Entries From Git Stash](git/clear-entries-from-git-stash.md)
- [Clone A Repo Just For The Files, Without History](git/clone-a-repo-just-for-the-files-without-history.md)
- [Clone A Repo Locally From .git](git/clone-a-repo-locally-from-git.md)
- [Configure Global gitignore File](git/configure-global-gitignore-file.md)
- [Configuring The Pager](git/configuring-the-pager.md)
- [Copy A File From Another Branch](git/copy-a-file-from-another-branch.md)
- [Count All Files Of Specific Type Tracked By Git](git/count-all-files-of-specific-type-tracked-by-git.md)
- [Count Number Of Commits On A Branch](git/count-number-of-commits-on-a-branch.md)
- [Create A New Branch With Git Switch](git/create-a-new-branch-with-git-switch.md)
- [Delete All Untracked Files](git/delete-all-untracked-files.md)
- [Determine The Hash Id For A Blob](git/determine-the-hash-id-for-a-blob.md)
@@ -306,17 +353,22 @@ _1534 TILs and counting..._
- [Dropping Commits With Git Rebase](git/dropping-commits-with-git-rebase.md)
- [Dry Runs in Git](git/dry-runs-in-git.md)
- [Exclude A File From A Diff Output](git/exclude-a-file-from-a-diff-output.md)
- [Exclude A Directory During A Command](git/exclude-a-directory-during-a-command.md)
- [Excluding Files Locally](git/excluding-files-locally.md)
- [Extend Git With Custom Commands](git/extend-git-with-custom-commands.md)
- [Files With Local Changes Cannot Be Removed](git/files-with-local-changes-cannot-be-removed.md)
- [Find And Remove Files That Match A Name](git/find-and-remove-files-that-match-a-name.md)
- [Find The Date That A File Was Added To The Repo](git/find-the-date-that-a-file-was-added-to-the-repo.md)
- [Find The Initial Commit](git/find-the-initial-commit.md)
- [Fix Whitespace Errors Throughout Branch Commits](git/fix-whitespace-errors-throughout-branch-commits.md)
- [Get Latest Commit Timestamp For A File](git/get-latest-commit-timestamp-for-a-file.md)
- [Get The Name Of The Current Branch](git/get-the-name-of-the-current-branch.md)
- [Get The Short Version Of The Latest Commit](git/get-the-short-version-of-the-latest-commit.md)
- [Grab A Single File From A Stash](git/grab-a-single-file-from-a-stash.md)
- [Grep For A Pattern On Another Branch](git/grep-for-a-pattern-on-another-branch.md)
- [Grep Over Commit Messages](git/grep-over-commit-messages.md)
- [Highlight Extra Whitespace In Diff Output](git/highlight-extra-whitespace-in-diff-output.md)
- [Highlight Small Change On Single Line](git/highlight-small-change-on-single-line.md)
- [Ignore Changes To A Tracked File](git/ignore-changes-to-a-tracked-file.md)
- [Ignore Files Specific To Your Workflow](git/ignore-files-specific-to-your-workflow.md)
- [Include A Message With Your Stashed Changes](git/include-a-message-with-your-stashed-changes.md)
@@ -327,7 +379,9 @@ _1534 TILs and counting..._
- [Interactively Unstage Changes](git/interactively-unstage-changes.md)
- [Keep File Locally With `git rm`](git/keep-file-locally-with-git-rm.md)
- [Last Commit A File Appeared In](git/last-commit-a-file-appeared-in.md)
- [List All Files Added During Span Of Time](git/list-all-files-added-during-span-of-time.md)
- [List All Files Changed Between Two Branches](git/list-all-files-changed-between-two-branches.md)
- [List All Git Aliases From gitconfig](git/list-all-git-aliases-from-gitconfig.md)
- [List Branches That Contain A Commit](git/list-branches-that-contain-a-commit.md)
- [List Commits On A Branch](git/list-commits-on-a-branch.md)
- [List Different Commits Between Two Branches](git/list-different-commits-between-two-branches.md)
@@ -344,15 +398,18 @@ _1534 TILs and counting..._
- [Quicker Commit Fixes With The Fixup Flag](git/quicker-commit-fixes-with-the-fixup-flag.md)
- [Rebase Commits With An Arbitrary Command](git/rebase-commits-with-an-arbitrary-command.md)
- [Reference A Commit Via Commit Message Pattern Matching](git/reference-a-commit-via-commit-message-pattern-matching.md)
- [Reference Commits Earlier Than Reflog Remembers](git/reference-commits-earlier-than-reflog-remembers.md)
- [Remove Untracked Files From A Directory](git/remove-untracked-files-from-a-directory.md)
- [Rename A Remote](git/rename-a-remote.md)
- [Renaming A Branch](git/renaming-a-branch.md)
- [Resetting A Reset](git/resetting-a-reset.md)
- [Resolve A Merge Conflict From Stash Pop](git/resolve-a-merge-conflict-from-stash-pop.md)
- [Restore File From One Branch To The Current](git/restore-file-from-one-branch-to-the-current.md)
- [Review Commits From Before A Certain Date](git/review-commits-from-before-a-certain-date.md)
- [Run A Git Command From Outside The Repo](git/run-a-git-command-from-outside-the-repo.md)
- [Set A Custom Pager For A Specific Command](git/set-a-custom-pager-for-a-specific-command.md)
- [Set Default Branch Name For New Repos](git/set-default-branch-name-for-new-repos.md)
- [Set Up GPG Signing Key](git/set-up-gpg-signing-key.md)
- [Shorthand To Force Push A Branch](git/shorthand-to-force-push-a-branch.md)
- [Show All Commits For A File Beyond Renaming](git/show-all-commits-for-a-file-beyond-renaming.md)
- [Show Changes For Files That Match A Pattern](git/show-changes-for-files-that-match-a-pattern.md)
@@ -360,6 +417,7 @@ _1534 TILs and counting..._
- [Show File Diffs When Viewing Git Log](git/show-file-diffs-when-viewing-git-log.md)
- [Show List Of Most Recently Committed Branches](git/show-list-of-most-recently-committed-branches.md)
- [Show Only Commits That Touch Specific Lines](git/show-only-commits-that-touch-specific-lines.md)
- [Show Summary Stats For Current Branch](git/show-summary-stats-for-current-branch.md)
- [Show The diffstat Summary Of A Commit](git/show-the-diffstat-summary-of-a-commit.md)
- [Show The Good And The Bad With Git Bisect](git/show-the-good-and-the-bad-with-git-bisect.md)
- [Show What Is In A Stash](git/show-what-is-in-a-stash.md)
@@ -380,6 +438,7 @@ _1534 TILs and counting..._
- [Untrack A Directory Of Files Without Deleting](git/untrack-a-directory-of-files-without-deleting.md)
- [Untrack A File Without Deleting It](git/untrack-a-file-without-deleting-it.md)
- [Update The URL Of A Remote](git/update-the-url-of-a-remote.md)
- [Use External Diff Tool Like Difftastic](git/use-external-diff-tool-like-difftastic.md)
- [Using Commands With A Relative Date Format](git/using-commands-with-a-relative-date-format.md)
- [Verbose Commit Message](git/verbose-commit-message.md)
- [Viewing A File On Another Branch](git/viewing-a-file-on-another-branch.md)
@@ -387,6 +446,13 @@ _1534 TILs and counting..._
- [What Is The Current Branch?](git/what-is-the-current-branch.md)
- [Whitespace Warnings](git/whitespace-warnings.md)
### GitHub
- [Access Your GitHub Profile Photo](github/access-your-github-profile-photo.md)
- [Open A PR To An Unforked Repo](github/open-a-pr-to-an-unforked-repo.md)
- [Target Another Repo When Creating A PR](github/target-another-repo-when-creating-a-pr.md)
- [Tell gh What The Default Repo Is](github/tell-gh-what-the-default-repo-is.md)
### GitHub Actions
- [Cache Playwright Dependencies Across Workflows](github-actions/cache-playwright-dependencies-across-workflows.md)
@@ -394,22 +460,36 @@ _1534 TILs and counting..._
- [Disable A Workflow With The gh CLI](github-actions/disable-a-workflow-with-the-gh-cli.md)
- [Reference An Encrypted Secret In An Action](github-actions/reference-an-encrypted-secret-in-an-action.md)
- [Trigger A Workflow Via An API Call](github-actions/trigger-a-workflow-via-an-api-call.md)
- [Use Labels To Block PR Merge](github-actions/use-labels-to-block-pr-merge.md)
### Go
- [Access Go Docs Offline](go/access-go-docs-offline.md)
- [Add A Method To A Struct](go/add-a-method-to-a-struct.md)
- [Basic Delve Debugging Session](go/basic-delve-debugging-session.md)
- [Build For A Specific OS And Architecture](go/build-for-a-specific-os-and-architecture.md)
- [Check If Cobra Flag Was Set](go/check-if-cobra-flag-was-set.md)
- [Combine Two Slices](go/combine-two-slices.md)
- [Configure Max String Print Length For Delve](go/configure-max-string-print-length-for-delve.md)
- [Connect To A SQLite Database](go/connect-to-a-sqlite-database.md)
- [Create A Slice From An Array](go/create-a-slice-from-an-array.md)
- [Detect If Stdin Comes From A Redirect](go/detect-if-stdin-comes-from-a-redirect.md)
- [Deterministically Seed A Random Number Generator](go/deterministically-seed-a-random-number-generator.md)
- [Difference Between Slice And Pointer To Slice](go/difference-between-slice-and-pointer-to-slice.md)
- [Do Something N Times](go/do-something-n-times.md)
- [Find Executables Installed By Go](go/find-executables-installed-by-go.md)
- [Format Date And Time With Time Constants](go/format-date-and-time-with-time-constants.md)
- [Not So Random](go/not-so-random.md)
- [Parse A String Into Individual Fields](go/parse-a-string-into-individual-fields.md)
- [Parse Flags From CLI Arguments](go/parse-flags-from-cli-arguments.md)
- [Pass A Struct To A Function](go/pass-a-struct-to-a-function.md)
- [Produce The Zero Value Of A Generic Type](go/produce-the-zero-value-of-a-generic-type.md)
- [Redirect File To Stdin During Delve Debug](go/redirect-file-to-stdin-during-delve-debug.md)
- [Replace The Current Process With An External Command](go/replace-the-current-process-with-an-external-command.md)
- [Sleep For A Duration](go/sleep-for-a-duration.md)
- [Sort Slice In Ascending Or Descending Order](go/sort-slice-in-ascending-or-descending-order.md)
- [Upgrading From An Older Version On Mac](go/upgrading-from-an-older-version-on-mac.md)
- [Write A Custom Scan Function For File IO](go/write-a-custom-scan-function-for-file-io.md)
### GROQ
@@ -426,13 +506,16 @@ _1534 TILs and counting..._
- [Open Dashboard For Specific Add-On](heroku/open-dashboard-for-specific-add-on.md)
- [Run SQL Against Remote Postgres Database](heroku/run-sql-against-remote-postgres-database.md)
- [Set And Show Heroku Env Variables](heroku/set-and-show-heroku-env-variables.md)
- [Specify Default Team And App For Project](heroku/specify-default-team-and-app-for-project.md)
- [SSH Into Heroku Server Hosting App](heroku/ssh-into-heroku-server-hosting-app.md)
### HTML
- [Adding Alt Text To An Image](html/adding-alt-text-to-an-image.md)
- [Allow Number Input To Accept Decimal Values](html/allow-number-input-to-accept-decimal-values.md)
- [Determine Which Button Submitted The Form](html/determine-which-button-submitted-the-form.md)
- [Disable Auto-Completion For A Form Input](html/disable-auto-completion-for-a-form-input.md)
- [Disclose Additional Details](html/disclose-additional-details.md)
- [Make Elements Non-Interactive With Inert](html/make-elements-non-interactive-with-inert.md)
- [Prevent Search Engines From Indexing A Page](html/prevent-search-engines-from-indexing-a-page.md)
- [Render Text As Superscript](html/render-text-as-superscript.md)
@@ -454,12 +537,14 @@ _1534 TILs and counting..._
- [Analyze Your Website Performance](internet/analyze-your-website-performance.md)
- [Check Your Public IP Address](internet/check-your-public-ip-address.md)
- [Digraph Unicode Characters Have A Titlecase](internet/digraph-unicode-characters-have-a-titlecase.md)
- [Download A Google Doc As Specific Format](internet/download-a-google-doc-as-specific-format.md)
- [Enable Keyboard Shortcuts In Gmail](internet/enable-keyboard-shortcuts-in-gmail.md)
- [Exclude AI Overview From Google Search](internet/exclude-ai-overview-from-google-search.md)
- [Exclude Whitespace Changes From GitHub Diffs](internet/exclude-whitespace-changes-from-github-diffs.md)
- [Figure Out Your Public IP Address](internet/figure-out-your-public-ip-address.md)
- [Focus The URL Bar](internet/focus-the-url-bar.md)
- [Get Random Images From Unsplash](internet/get-random-images-from-unsplash.md)
- [Grab The RSS Feed For A Substack Blog](internet/grab-the-rss-feed-for-a-substack-blog.md)
- [Search Tweets By Author](internet/search-tweets-by-author.md)
- [Show All Pivotal Stories With Blockers](internet/show-all-pivotal-stories-with-blockers.md)
- [Verify Site Ownership With DNS Record](internet/verify-site-ownership-with-dns-record.md)
@@ -506,6 +591,7 @@ _1534 TILs and counting..._
- [Find Where Yarn Is Installing Binaries](javascript/find-where-yarn-is-installing-binaries.md)
- [for...in Iterates Over Object Properties](javascript/for-in-iterates-over-object-properties.md)
- [Format A Decimal To A Fixed Number Of Digits](javascript/format-a-decimal-to-a-fixed-number-of-digits.md)
- [Format A List Of Items By Locale](javascript/format-a-list-of-items-by-locale.md)
- [Format Time Zone Identifier](javascript/format-time-zone-identifier.md)
- [Formatting Values With Units For Display](javascript/formatting-values-with-units-for-display.md)
- [Freeze An Object, Sorta](javascript/freeze-an-object-sorta.md)
@@ -579,7 +665,9 @@ _1534 TILs and counting..._
### jj
- [Colocate jj And git Directories For Project](jj/colocate-jj-and-git-directories-for-project.md)
- [Describe Current Changes And Create New Change](jj/describe-current-changes-and-create-new-change.md)
- [Find System-wide Config File For User](jj/find-system-wide-config-file-for-user.md)
- [Squash Changes Into Parent Commit Interactively](jj/squash-changes-into-parent-commit-interactively.md)
### jq
@@ -621,18 +709,24 @@ _1534 TILs and counting..._
- [Access All Screen And Video Capture Options](mac/access-all-screen-and-video-capture-options.md)
- [Access System Information On OS X](mac/access-system-information-on-osx.md)
- [Access Unsupported Screen Resolutions With RDM](mac/access-unsupported-screen-resolutions-with-rdm.md)
- [Add A Bunch Of CLI Utilities With coreutils](mac/add-a-bunch-of-cli-utilities-with-coreutils.md)
- [Capture Screenshot To Clipboard From CLI](mac/capture-screenshot-to-clipboard-from-cli.md)
- [Check Network Quality Stats From The Command Line](mac/check-network-quality-stats-from-the-command-line.md)
- [Clean Up Old Homebrew Files](mac/clean-up-old-homebrew-files.md)
- [Convert An HEIC Image File To JPG](mac/convert-an-heic-image-file-to-jpg.md)
- [Default Screenshot Location](mac/default-screenshot-location.md)
- [Detect How Long A User Has Been Idle](mac/detect-how-long-a-user-has-been-idle.md)
- [Disable Swipe Navigation For A Specific App](mac/disable-swipe-navigation-for-a-specific-app.md)
- [Display A Message With Alfred](mac/display-a-message-with-alfred.md)
- [Find The Process Using A Specific Port](mac/find-the-process-using-a-specific-port.md)
- [Gesture For Viewing All Windows Of Current App](mac/gesture-for-viewing-all-windows-of-current-app.md)
- [Insert A Non-Breaking Space Character](mac/insert-a-non-breaking-space-character.md)
- [Inspect Assertions Preventing Sleep](mac/inspect-assertions-preventing-sleep.md)
- [Keyboard Shortcuts For Interesting With Text Areas](mac/keyboard-shortcuts-for-interacting-with-text-areas.md)
- [Launch Some Confetti](mac/launch-some-confetti.md)
- [List All The Say Voices](mac/list-all-the-say-voices.md)
- [Open Finder.app To Specific Directory](mac/open-finder-app-to-specific-directory.md)
- [Prevent Sleep With The Caffeinate Command](mac/prevent-sleep-with-the-caffeinate-command.md)
- [Quickly Type En Dashes And Em Dashes](mac/quickly-type-en-dashes-and-em-dashes.md)
- [Require Additional JS Libraries In Postman](mac/require-additional-js-libraries-in-postman.md)
- [Resize App Windows With AppleScript](mac/resize-app-windows-with-applescript.md)
@@ -641,10 +735,21 @@ _1534 TILs and counting..._
- [Run AppleScript Commands Inline In The Terminal](mac/run-applescript-commands-inline-in-the-terminal.md)
- [Set A Window To Its Default Zoom Level](mac/set-a-window-to-its-default-zoom-level.md)
- [Specify App When Opening From Command Line](mac/specify-app-when-opening-from-command-line.md)
- [Start Amphetamine Session With AppleScript](mac/start-amphetamine-session-with-applescript.md)
- [Uninstall LogiTech G Hub From Mac](mac/uninstall-logitech-g-hub-from-mac.md)
- [Use A Different Font With iTerm2](mac/use-a-different-font-with-iterm2.md)
- [Use Default Screenshot Shortcuts With CleanShot X](mac/use-default-screenshot-shortcuts-with-cleanshot-x.md)
- [View All Windows Of The Current App](mac/view-all-windows-of-the-current-app.md)
- [Write System Clipboard To A File](mac/write-system-clipboard-to-a-file.md)
### Mise
- [Create Umbrella Task For All Test Tasks](mise/create-umbrella-task-for-all-test-tasks.md)
- [List The Files Being Loaded By Mise](mise/list-the-files-being-loaded-by-mise.md)
- [Preserve Color Output For Task Command](mise/preserve-color-output-for-task-command.md)
- [Read Existing Dot Env File Into Env Vars](mise/read-existing-dot-env-file-into-env-vars.md)
- [Run A Command With Specific Tool Version](mise/run-a-command-with-specific-tool-version.md)
### MongoDB
- [Determine The Database Version](mongodb/determine-the-database-version.md)
@@ -662,6 +767,7 @@ _1534 TILs and counting..._
- [Doing Date Math](mysql/doing-date-math.md)
- [Dump A Database To A File](mysql/dump-a-database-to-a-file.md)
- [Echo A Message From A SQL File](mysql/echo-a-message-from-a-sql-file.md)
- [Get Idea Of What Is In A JSON Column](mysql/get-idea-of-what-is-in-a-json-column.md)
- [Ignore Duplicates When Inserting Records](mysql/ignore-duplicates-when-inserting-records.md)
- [List Databases And Tables](mysql/list-databases-and-tables.md)
- [Run Statements In A Transaction](mysql/run-statements-in-a-transaction.md)
@@ -675,7 +781,9 @@ _1534 TILs and counting..._
- [Allow Neovim To Copy/Paste With System Clipboard](neovim/allow-neovim-to-copy-paste-with-system-clipboard.md)
- [Create User Command To Open Init Config](neovim/create-user-command-to-open-init-config.md)
- [Jump Between Changes In Current File](neovim/jump-between-changes-in-current-file.md)
- [Run A Lua Statement From The Command Prompt](neovim/run-a-lua-statement-from-the-command-prompt.md)
- [Run nvim With Factory Defaults](neovim/run-nvim-with-factory-defaults.md)
- [Set Up Vim-Plug With Neovim](neovim/set-up-vim-plug-with-neovim.md)
### Netlify
@@ -713,6 +821,7 @@ _1534 TILs and counting..._
### Planetscale
- [See What Databases You Have Access To](planetscale/see-what-databases-you-have-access-to.md)
- [Seed Production Data Into Another Branch](planetscale/seed-production-data-into-another-branch.md)
### pnpm
@@ -739,6 +848,7 @@ _1534 TILs and counting..._
- [Check If The Local Server Is Running](postgres/check-if-the-local-server-is-running.md)
- [Check If User Role Exists For Database](postgres/check-if-user-role-exists-for-database.md)
- [Check Table For Any Oprhaned Records](postgres/check-table-for-any-orphaned-records.md)
- [Check The Size Of Databases In A Cluster](postgres/check-the-size-of-databases-in-a-cluster.md)
- [Checking Inequality](postgres/checking-inequality.md)
- [Checking The Type Of A Value](postgres/checking-the-type-of-a-value.md)
- [Clear The Screen In psql](postgres/clear-the-screen-in-psql.md)
@@ -752,12 +862,14 @@ _1534 TILs and counting..._
- [Convert A String To A Timestamp](postgres/convert-a-string-to-a-timestamp.md)
- [Count How Many Records There Are Of Each Type](postgres/count-how-many-records-there-are-of-each-type.md)
- [Count Records By Type](postgres/count-records-by-type.md)
- [Count The Number Of Items In An Array](postgres/count-the-number-of-items-in-an-array.md)
- [Count The Number Of Trues In An Aggregate Query](postgres/count-the-number-of-trues-in-an-aggregate-query.md)
- [Create A Cluster In A Specific Data Directory](postgres/create-a-cluster-in-a-specific-data-directory.md)
- [Create A Composite Primary Key](postgres/create-a-composite-primary-key.md)
- [Create A Table From The Structure Of Another](postgres/create-a-table-from-the-structure-of-another.md)
- [Create An Index Across Two Columns](postgres/create-an-index-across-two-columns.md)
- [Create An Index Without Locking The Table](postgres/create-an-index-without-locking-the-table.md)
- [Create And Execute SQL Statements With \gexec](postgres/create-and-execute-sql-statements-with-gexec.md)
- [Create Database Uses Template1](postgres/create-database-uses-template1.md)
- [Create hstore From Two Arrays](postgres/create-hstore-from-two-arrays.md)
- [Create Table Adds A Data Type](postgres/create-table-adds-a-data-type.md)
@@ -782,6 +894,7 @@ _1534 TILs and counting..._
- [Escaping String Literals With Dollar Quoting](postgres/escaping-string-literals-with-dollar-quoting.md)
- [Export Query Results To A CSV](postgres/export-query-results-to-a-csv.md)
- [Extracting Nested JSON Data](postgres/extracting-nested-json-data.md)
- [Fetch Data From An Endpoint In SQL](postgres/fetch-data-from-an-endpoint-in-sql.md)
- [Fetch Specific Number Of Results](postgres/fetch-specific-number-of-results.md)
- [Find Duplicate Records In Table Without Unique Id](postgres/find-duplicate-records-in-table-without-unique-id.md)
- [Find Records That Contain Duplicate Values](postgres/find-records-that-contain-duplicate-values.md)
@@ -840,6 +953,7 @@ _1534 TILs and counting..._
- [Prevent A Query From Running Too Long](postgres/prevent-a-query-from-running-too-long.md)
- [Print The Query Buffer In psql](postgres/print-the-query-buffer-in-psql.md)
- [Put Unique Constraint On Generated Column](postgres/put-unique-constraint-on-generated-column.md)
- [References Target Primary Key By Default](postgres/references-target-primary-key-by-default.md)
- [Remove Not Null Constraint From A Column](postgres/remove-not-null-constraint-from-a-column.md)
- [Renaming A Sequence](postgres/renaming-a-sequence.md)
- [Renaming A Table](postgres/renaming-a-table.md)
@@ -850,9 +964,11 @@ _1534 TILs and counting..._
- [Set Inclusion With hstore](postgres/set-inclusion-with-hstore.md)
- [Set A Seed For The Random Number Generator](postgres/set-a-seed-for-the-random-number-generator.md)
- [Set A Statement Timeout Threshold For A Session](postgres/set-a-statement-timeout-threshold-for-a-session.md)
- [Set Up A Project-Local Cluster With Postgres.app](postgres/set-up-a-project-local-cluster-with-postgres-app.md)
- [Sets With The Values Command](postgres/sets-with-the-values-command.md)
- [Shorthand Absolute Value Operator](postgres/shorthand-absolute-value-operator.md)
- [Show All Versions Of An Operator](postgres/show-all-versions-of-an-operator.md)
- [Show Reconstructed Constraints For A Table](postgres/show-reconstructed-constraints-for-a-table.md)
- [Show The Hidden Queries Behind Backslash Commands](postgres/show-the-hidden-queries-behind-backslash-commands.md)
- [Sleeping](postgres/sleeping.md)
- [Special Math Operators](postgres/special-math-operators.md)
@@ -869,12 +985,14 @@ _1534 TILs and counting..._
- [Timestamp Functions](postgres/timestamp-functions.md)
- [Toggling The Pager In PSQL](postgres/toggling-the-pager-in-psql.md)
- [Track psql History Separately Per Database](postgres/track-psql-history-separately-per-database.md)
- [Trim Leading And Trailing Space From String](postgres/trim-leading-and-trailing-space-from-string.md)
- [Truncate All Rows](postgres/truncate-all-rows.md)
- [Truncate Tables With Dependents](postgres/truncate-tables-with-dependents.md)
- [Turning Timing On](postgres/turn-timing-on.md)
- [Two Ways To Compute Factorial](postgres/two-ways-to-compute-factorial.md)
- [Two Ways To Escape A Quote In A String](postgres/two-ways-to-escape-a-quote-in-a-string.md)
- [Types By Category](postgres/types-by-category.md)
- [Unable To Infer Data Type In Production](postgres/unable-to-infer-data-type-in-production.md)
- [Union All Rows Including Duplicates](postgres/union-all-rows-including-duplicates.md)
- [Use A psqlrc File For Common Settings](postgres/use-a-psqlrc-file-for-common-settings.md)
- [Use A Trigger To Mirror Inserts To Another Table](postgres/use-a-trigger-to-mirror-inserts-to-another-table.md)
@@ -903,6 +1021,7 @@ _1534 TILs and counting..._
### Python
- [Access Instance Variables](python/access-instance-variables.md)
- [Break Debugger On First Line Of Program](python/break-debugger-on-first-line-of-program.md)
- [Create A Dummy DataFrame In Pandas](python/create-a-dummy-dataframe-in-pandas.md)
- [Dunder Methods](python/dunder-methods.md)
- [Override The Boolean Context Of A Class](python/override-the-boolean-context-of-a-class.md)
@@ -912,21 +1031,25 @@ _1534 TILs and counting..._
### Rails
- [Access Secrets In A Rails 5.2 App](rails/access-secrets-in-a-rails-5-2-app.md)
- [ActiveRecord Query For This Or That](rails/active-record-query-for-this-or-that.md)
- [Add A Check Constraint To A Table](rails/add-a-check-constraint-to-a-table.md)
- [Add A Database Index If It Does Not Already Exist](rails/add-a-database-index-if-it-does-not-already-exist.md)
- [Add A Foreign Key Reference To A Table](rails/add-a-foreign-key-reference-to-a-table.md)
- [Add A Generated Column To A PostgreSQL Table](rails/add-a-generated-column-to-a-postgresql-table.md)
- [Add A Reference Column With An Index](rails/add-a-reference-column-with-an-index.md)
- [Add ActiveRecord Error Not Tied To Any Attribute](rails/add-activerecord-error-not-tied-to-any-attribute.md)
- [Add Color To The IRB Console Prompt](rails/add-color-to-the-irb-console-prompt.md)
- [Add React With Webpacker To A New Rails App](rails/add-react-with-webpacker-to-a-new-rails-app.md)
- [Add timestamptz Columns With The Migration DSL](rails/add-timestamptz-columns-with-the-migration-dsl.md)
- [Access Secrets In A Rails 5.2 App](rails/access-secrets-in-a-rails-5-2-app.md)
- [ActiveRecord Query For This Or That](rails/active-record-query-for-this-or-that.md)
- [Adjust The Production Log Level](rails/adjust-the-production-log-level.md)
- [Advance The Date](rails/advance-the-date.md)
- [Allow Associations To Be Optional](rails/allow-associations-to-be-optional.md)
- [Allow List Params Anywhere With Strong Params](rails/allow-list-params-anywhere-with-strong-params.md)
- [All or Nothing Database Transactions](rails/all-or-nothing-database-transactions.md)
- [Alphabetize Schema Columns To Keep Them Consistent](rails/alphabetize-schema-columns-to-keep-them-consistent.md)
- [Alter The Rails Setup Script](rails/alter-the-rails-setup-script.md)
- [Apply Basic HTML Formatting To Block Of Text](rails/apply-basic-html-formatting-to-block-of-text.md)
- [Assert Two Arrays Have The Same Items With RSpec](rails/assert-two-arrays-have-the-same-items-with-rspec.md)
- [Attach A File With Capybara](rails/attach-a-file-with-capybara.md)
- [Attribute Getter without the Recursion](rails/attribute-getter-without-the-recursion.md)
@@ -947,6 +1070,7 @@ _1534 TILs and counting..._
- [Comparing DateTimes Down To Second Precision](rails/comparing-datetimes-down-to-second-precision.md)
- [Conditional Class Selectors in Haml](rails/conditional-class-selectors-in-haml.md)
- [Convert A Symbol To A Constant](rails/convert-a-symbol-to-a-constant.md)
- [Convert JSON Field To Hash With Indifferent Access](rails/convert-json-field-to-hash-with-indifferent-access.md)
- [Count The Number Of Records By Attribute](rails/count-the-number-of-records-by-attribute.md)
- [Create A Custom Named References Column](rails/create-a-custom-named-references-column.md)
- [Create A Join Table With The Migration DSL](rails/create-a-join-table-with-the-migration-dsl.md)
@@ -954,19 +1078,26 @@ _1534 TILs and counting..._
- [Creating Records of Has_One Associations](rails/creating-records-of-has-one-associations.md)
- [Custom Validation Message](rails/custom-validation-message.md)
- [Customize Paths And Helpers For Devise Routes](rails/customize-paths-and-helpers-for-devise-routes.md)
- [Customize Template For New Schema Migration](rails/customize-template-for-new-schema-migration.md)
- [Customize The Path Of A Resource Route](rails/customize-the-path-of-a-resource-route.md)
- [Define The Root Path For The App](rails/define-the-root-path-for-the-app.md)
- [Delete Paranoid Records](rails/delete-paranoid-records.md)
- [Demodulize A Class Name](rails/demodulize-a-class-name.md)
- [Determine The Configured Primary Key Type](rails/determine-the-configured-primary-key-type.md)
- [Different Ways To Add A Foreign Key Reference](rails/different-ways-to-add-a-foreign-key-reference.md)
- [Disambiguate Where In A Joined Relation](rails/disambiguate-where-in-a-joined-relation.md)
- [Empty find_by Returns First Record](rails/empty-find-by-returns-first-record.md)
- [Enforce Locals Passed To A Partial](rails/enforce-locals-passed-to-a-partial.md)
- [Ensure A Rake Task Cannot Write Data](rails/ensure-a-rake-task-cannot-write-data.md)
- [Ensure Migrations Use The Latest Schema](rails/ensure-migrations-use-the-latest-schema.md)
- [Ensure Record Saved With after_commit Callback](rails/ensure-record-saved-with-after-commit-callback.md)
- [Filter ActiveModel Validation Errors](rails/filter-active-model-validation-errors.md)
- [Filter ActiveStorage Blobs To Only Images](rails/filter-active-storage-blobs-to-only-images.md)
- [Find Or Create A Record With FactoryBot](rails/find-or-create-a-record-with-factory-bot.md)
- [Find Records With Multiple Associated Records](rails/find-records-with-multiple-associated-records.md)
- [Force All Users To Sign Out](rails/force-all-users-to-sign-out.md)
- [Format DateTime With Builtin Formats](rails/format-datetime-with-builtin-formats.md)
- [Format Specific html.erb Template Files](rails/format-specific-html-erb-template-files.md)
- [Generate A Model](rails/generate-a-model.md)
- [Generate A Rails App From The Main Branch](rails/generate-a-rails-app-from-the-main-branch.md)
- [Generating And Executing SQL](rails/generating-and-executing-sql.md)
@@ -983,6 +1114,7 @@ _1534 TILs and counting..._
- [Hash Slicing](rails/hash-slicing.md)
- [Ignore Poltergeist JavaScript Errors](rails/ignore-poltergeist-javascript-errors.md)
- [Include Devise Helpers In Your Controller Tests](rails/include-devise-helpers-in-your-controller-tests.md)
- [Inspect Configuration Of Database Connection](rails/inspect-configuration-of-database-connection.md)
- [Inspect Previous Changes To ActiveRecord Object](rails/inspect-previous-changes-to-activerecord-object.md)
- [Link To The Current Page With Query Params](rails/link-to-the-current-page-with-query-params.md)
- [List All Installable Rails Versions](rails/list-all-installable-rails-versions.md)
@@ -995,6 +1127,7 @@ _1534 TILs and counting..._
- [Make A String Attribute Easy To Inquire About](rails/make-a-string-attribute-easy-to-inquire-about.md)
- [Make ActionMailer Synchronous In Test](rails/make-action-mailer-synchronous-in-test.md)
- [Make Remove Column Migration Reversible](rails/make-remove-column-migration-reversible.md)
- [Manage Timestamps With Upsert](rails/manage-timestamps-with-upsert.md)
- [Manually Run A Migration From Rails Console](rails/manually-run-a-migration-from-rails-console.md)
- [Mark For Destruction](rails/mark-for-destruction.md)
- [Mask An ActiveRecord Attribute](rails/mask-an-activerecord-attribute.md)
@@ -1002,6 +1135,8 @@ _1534 TILs and counting..._
- [Migrating Up Down Up](rails/migrating-up-down-up.md)
- [Mock Rails Environment With An Inquiry Instance](rails/mock-rails-environment-with-an-inquiry-instance.md)
- [Order Matters For `rescue_from` Blocks](rails/order-matters-for-rescue-from-blocks.md)
- [Override Text Displayed By Form Label](rails/override-text-displayed-by-form-label.md)
- [Parameterize A String With Underscores](rails/parameterize-a-string-with-underscores.md)
- [Params Includes Submission Button Info](rails/params-includes-submission-button-info.md)
- [Params Is A Hash With Indifferent Access](rails/params-is-a-hash-with-indifferent-access.md)
- [Parse Query Params From A URL](rails/parse-query-params-from-a-url.md)
@@ -1010,10 +1145,13 @@ _1534 TILs and counting..._
- [Polymorphic Path Helpers](rails/polymorphic-path-helpers.md)
- [Prefer select_all Over execute For Read Queries](rails/prefer-select-all-over-execute-for-read-queries.md)
- [Pretend Generations](rails/pretend-generations.md)
- [Prevent Mailer Previews From Cluttering Database](rails/prevent-mailer-previews-from-cluttering-database.md)
- [Prevent Writes With A Sandboxed Rails Console](rails/prevent-writes-with-a-sandboxed-rails-console.md)
- [Provide Fake Form Helper To Controllers](rails/provide-fake-form-helper-to-controllers.md)
- [Query A Single Value From The Database](rails/query-a-single-value-from-the-database.md)
- [Read In Environment-Specific Config Values](rails/read-in-environment-specific-config-values.md)
- [Read-Only Models](rails/read-only-models.md)
- [Rebuild Tailwind Bundle For Dev Server](rails/rebuild-tailwind-bundle-for-dev-server.md)
- [Remove A Database Column From A Table](rails/remove-a-database-column-from-a-table.md)
- [Remove The Default Value On A Column](rails/remove-the-default-value-on-a-column.md)
- [Render An Alternative ActionMailer Template](rails/render-an-alternative-action-mailer-template.md)
@@ -1022,14 +1160,19 @@ _1534 TILs and counting..._
- [Rescue From](rails/rescue-from.md)
- [Rescue From With A Separate Method](rails/rescue-from-with-a-separate-method.md)
- [Respond With JSON Regardless of Content Type](rails/respond-with-json-regardless-of-content-type.md)
- [Restart Puma Server By Touching Restart File](rails/restart-puma-server-by-touching-restart-file.md)
- [Retrieve An Object If It Exists](rails/retrieve-an-object-if-it-exists.md)
- [Rollback A Couple Migrations](rails/rollback-a-couple-migrations.md)
- [Rollback A Specific Migration Out Of Order](rails/rollback-a-specific-migration-out-of-order.md)
- [Rounding Numbers With Precision](rails/rounding-numbers-with-precision.md)
- [Run A Rake Task Programmatically](rails/run-a-rake-task-programmatically.md)
- [Run Commands With Specific Rails Version](rails/run-commands-with-specific-rails-version.md)
- [Run Dev Processes With Overmind Instead Of Foreman](rails/run-dev-processes-with-overmind-instead-of-foreman.md)
- [Run Rails Console With Remote Dokku App](rails/run-rails-console-with-remote-dokku-app.md)
- [Run Some Code Whenever Rails Console Starts](rails/run-some-code-whenever-rails-console-starts.md)
- [Scaffold Auth Functionality With Rails 8 Generator](rails/scaffold-auth-functionality-with-rails-8-generator.md)
- [Schedule Sidekiq Jobs Out Into The Future](rails/schedule-sidekiq-jobs-out-into-the-future.md)
- [Scope Records To A Lower Or Upper Bound](rails/scope-records-to-a-lower-or-upper-bound.md)
- [Secure Passwords With Rails And Bcrypt](rails/secure-passwords-with-rails-and-bcrypt.md)
- [Select A Select By Selector](rails/select-a-select-by-selector.md)
- [Select A Specific Rails Version To Install](rails/select-a-specific-rails-version-to-install.md)
@@ -1039,6 +1182,7 @@ _1534 TILs and counting..._
- [Set DateTime To Include Time Zone In Migrations](rails/set-datetime-to-include-time-zone-in-migrations.md)
- [Set Default As SQL Function In Migration](rails/set-default-as-sql-function-in-migration.md)
- [Set default_url_options For Entire Application](rails/set-default-url-options-for-entire-application.md)
- [Set Meta Tags In ERB Views](rails/set-meta-tags-in-erb-views.md)
- [Set Schema Search Path](rails/set-schema-search-path.md)
- [Set Statement Timeout For All Postgres Connections](rails/set-statement-timeout-for-all-postgres-connections.md)
- [Set The Default Development Port](rails/set-the-default-development-port.md)
@@ -1057,6 +1201,7 @@ _1534 TILs and counting..._
- [Update Column Versus Update Attribute](rails/update-column-versus-update-attribute.md)
- [Upgrading Your Manifest For Sprocket's 4](rails/upgrading-your-manifest-for-sprockets-4.md)
- [Use IRB And Ruby Flags With Rails Console](rails/use-irb-and-ruby-flags-with-rails-console.md)
- [Use .ruby Extension For Template File](rails/use-ruby-extension-for-template-file.md)
- [Useful ActiveSupport Constants For Durations](rails/useful-active-support-constants-for-durations.md)
- [Validate Column Data With Check Constraints](rails/validate-column-data-with-check-constraints.md)
- [Verify And Read A Signed Cookie Value](rails/verify-and-read-a-signed-cookie-value.md)
@@ -1196,8 +1341,9 @@ _1534 TILs and counting..._
- [Add Progress Reporting To Long-Running Script](ruby/add-progress-reporting-to-long-running-script.md)
- [Are They All True?](ruby/are-they-all-true.md)
- [Assert About An Object's Attributes With RSpec](ruby/assert-about-an-objects-attributes-with-rspec.md)
- [Audit Your Ruby Project For Any CVEs](ruby/audit-your-ruby-project-for-any-cves.md)
- [Assoc For Hashes](ruby/assoc-for-hashes.md)
- [Audit Your Ruby Project For Any CVEs](ruby/audit-your-ruby-project-for-any-cves.md)
- [Avoid Double Negation With Minitest Refute](ruby/avoid-double-negation-with-minitest-refute.md)
- [Block Comments](ruby/block-comments.md)
- [Block Syntaxes Have Different Precedence](ruby/block-syntaxes-have-different-precedence.md)
- [Build HTTP And HTTPS URLs](ruby/build-http-and-https-urls.md)
@@ -1206,6 +1352,7 @@ _1534 TILs and counting..._
- [Check If A URL Resolves To 200](ruby/check-if-a-url-resolves-to-200.md)
- [Check If An Object Includes A Module](ruby/check-if-an-object-includes-a-module.md)
- [Check Return Status Of Running A Shell Command](ruby/check-return-status-of-running-a-shell-command.md)
- [Clamp To An Endless Range](ruby/clamp-to-an-endless-range.md)
- [Click On Text With Capybara](ruby/click-on-text-with-capybara.md)
- [Colorful Output With MiniTest](ruby/colorful-output-with-minitest.md)
- [Comparing Class Hierarchy Relationships](ruby/comparing-class-hierarchy-relationships.md)
@@ -1216,8 +1363,11 @@ _1534 TILs and counting..._
- [Create a CSV::Table Object](ruby/create-a-csv-table-object.md)
- [Create A Hash From An Array Of Arrays](ruby/create-a-hash-from-an-array-of-arrays.md)
- [Create Listing Of All Middleman Pages](ruby/create-listing-of-all-middleman-pages.md)
- [Create Mock Class That Can Be Overridden](ruby/create-mock-class-that-can-be-overridden.md)
- [Create A Module Of Utility Functions](ruby/create-a-module-of-utility-functions.md)
- [Create Named Structs With Struct.new](ruby/create-named-structs-with-struct-new.md)
- [Create Thumbnail Image For A PDF](ruby/create-thumbnail-image-for-a-pdf.md)
- [Decompose Unicode Character With Diacritic Mark](ruby/decompose-unicode-character-with-diacritic-mark.md)
- [Defaulting To Frozen String Literals](ruby/defaulting-to-frozen-string-literals.md)
- [Define A Custom RSpec Matcher](ruby/define-a-custom-rspec-matcher.md)
- [Define A Method On A Struct](ruby/define-a-method-on-a-struct.md)
@@ -1237,6 +1387,7 @@ _1534 TILs and counting..._
- [Exit A Process With An Error Message](ruby/exit-a-process-with-an-error-message.md)
- [Expect A Method To Be Called And Actually Call It](ruby/expect-a-method-to-be-called-and-actually-call-it.md)
- [Extract A Column Of Data From A CSV File](ruby/extract-a-column-of-data-from-a-csv-file.md)
- [Extract Capture Group Matches With String Slices](ruby/extract-capture-group-matches-with-string-slices.md)
- [FactoryGirl Sequences](ruby/factory-girl-sequences.md)
- [Fail](ruby/fail.md)
- [Fetch Warns About Superseding Block Argument](ruby/fetch-warns-about-superseding-block-argument.md)
@@ -1248,6 +1399,8 @@ _1534 TILs and counting..._
- [Generate A Signed JWT Token](ruby/generate-a-signed-jwt-token.md)
- [Generate Ruby Version And Gemset Files With RVM](ruby/generate-ruby-version-and-gemset-files-with-rvm.md)
- [Get Info About Your RubyGems Environment](ruby/get-info-about-your-ruby-gems-environment.md)
- [Get Specific Values From Arrays And Hashes](ruby/get-specific-values-from-hashes-and-arrays.md)
- [Get The Names Of The Month](ruby/get-the-names-of-the-month.md)
- [Get The Output Of Running A System Program](ruby/get-the-output-of-running-a-system-program.md)
- [Get UTC Offset For Different Time Zones](ruby/get-utc-offset-for-different-time-zones.md)
- [Identify Outdated Gems](ruby/identify-outdated-gems.md)
@@ -1255,14 +1408,18 @@ _1534 TILs and counting..._
- [Iterate With An Offset Index](ruby/iterate-with-an-offset-index.md)
- [Include Extra Context In A Honeybadger Notify](ruby/include-extra-context-in-a-honeybadger-notify.md)
- [Ins And Outs Of Pry](ruby/ins-and-outs-of-pry.md)
- [Install And Require Gems Inline Without Gemfile](ruby/install-and-require-gems-inline-without-gemfile.md)
- [Install Latest Version Of Ruby With asdf](ruby/install-latest-version-of-ruby-with-asdf.md)
- [Invoking Rake Tasks Multiple Times](ruby/invoking-rake-tasks-multiple-times.md)
- [IRB Has Built-In Benchmarking With Ruby 3](ruby/irb-has-built-in-benchmarking-with-ruby-3.md)
- [Join URI Path Parts](ruby/join-uri-path-parts.md)
- [Jump Out Of A Nested Context With Throw/Catch](ruby/jump-out-of-a-nested-context-with-throw-catch.md)
- [Last Raised Exception In The Call Stack](ruby/last-raised-exception-in-the-call-stack.md)
- [Limit Split](ruby/limit-split.md)
- [List The Running Ruby Version](ruby/list-the-running-ruby-version.md)
- [Listing Local Variables](ruby/listing-local-variables.md)
- [Make An Executable Ruby Script](ruby/make-an-executable-ruby-script.md)
- [Make Structs Easier To Use With Keyword Initialization](ruby/make-structs-easier-to-use-with-keyword-initialization.md)
- [Map With Index Over An Array](ruby/map-with-index-over-an-array.md)
- [Mock Method Chain Calls With RSpec](ruby/mock-method-chain-calls-with-rspec.md)
- [Mocking Requests With Partial URIs Using Regex](ruby/mocking-requests-with-partial-uris-using-regex.md)
@@ -1270,6 +1427,7 @@ _1534 TILs and counting..._
- [Named Regex Captures Are Assigned To Variables](ruby/named-regex-captures-are-assigned-to-variables.md)
- [Navigate Back In The Browser With Capybara](ruby/navigate-back-in-the-browser-with-capybara.md)
- [Next And Previous Floats](ruby/next-and-previous-floats.md)
- [OpenStruct Has Bad Performance Characteristics](ruby/open-struct-has-bad-performance-characteristics.md)
- [Or Operator Precedence](ruby/or-operator-precedence.md)
- [Output Bytecode For A Ruby Program](ruby/output-bytecode-for-a-ruby-program.md)
- [Override The Initial Sequence Value](ruby/override-the-initial-sequence-value.md)
@@ -1287,6 +1445,9 @@ _1534 TILs and counting..._
- [Question Mark Operator](ruby/question-mark-operator.md)
- [Rake Only Lists Tasks With Descriptions](ruby/rake-only-lists-tasks-with-descriptions.md)
- [Read The First Line From A File](ruby/read-the-first-line-from-a-file.md)
- [Refer To Implicit Block Argument With It](ruby/refer-to-implicit-block-argument-with-it.md)
- [Reference Hash Key With Safe Navigation](ruby/reference-hash-key-with-safe-navigation.md)
- [Regenerate Lock File With Newer Bundler](ruby/regenerate-lock-file-with-newer-bundler.md)
- [Rendering ERB](ruby/rendering-erb.md)
- [Replace The Current Process With An External Command](ruby/replace-the-current-process-with-an-external-command.md)
- [Require Entire Gemfile In Pry Session](ruby/require-entire-gemfile-in-pry-session.md)
@@ -1301,9 +1462,11 @@ _1534 TILs and counting..._
- [Scripting With RVM](ruby/scripting-with-rvm.md)
- [Scroll To Top Of Page With Capybara](ruby/scroll-to-top-of-page-with-capybara.md)
- [Search For Gem Versions Available To Install](ruby/search-for-gem-versions-available-to-install.md)
- [Set Default Tasks For Rake To Run](ruby/set-default-tasks-for-rake-to-run.md)
- [Set RVM Default Ruby](ruby/set-rvm-default-ruby.md)
- [Shift The Month On A Date Object](ruby/shift-the-month-on-a-date-object.md)
- [Show Public Methods With Pry](ruby/show-public-methods-with-pry.md)
- [Show The Bundler Location Of An Installed Gem](ruby/show-the-bundler-location-of-an-installed-gem.md)
- [Silence The Output Of A Ruby Statement In Pry](ruby/silence-the-output-of-a-ruby-statement-in-pry.md)
- [Single And Double Quoted String Notation](ruby/single-and-double-quoted-string-notation.md)
- [Skip Specific CVEs When Auditing Your Bundle](ruby/skip-specific-cves-when-auditing-your-bundle.md)
@@ -1344,6 +1507,7 @@ _1534 TILs and counting..._
- [OSX sed Does Regex A Bit Different](sed/osx-sed-does-regex-a-bit-different.md)
- [Output Only Lines Involved In A Substitution](sed/output-only-lines-involved-in-a-substitution.md)
- [Reference A Capture In The Regex](sed/reference-a-capture-in-the-regex.md)
- [Reference The Full Match In The Replacement](sed/reference-the-full-match-in-the-replacement.md)
- [Use An Alternative Delimiter In A Substitution](sed/use-an-alternative-delimiter-in-a-substitution.md)
### Shell
@@ -1354,6 +1518,7 @@ _1534 TILs and counting..._
### SQLite
- [Display Results In Readable Column Format](sqlite/display-results-in-readable-column-format.md)
- [Explore The Database Schema](sqlite/explore-the-database-schema.md)
### Streaming
@@ -1363,12 +1528,19 @@ _1534 TILs and counting..._
- [Apply Tailwind Classes To Existing CSS Class](tailwind/apply-tailwind-classes-to-existing-css-class.md)
- [Base Styles For Text Link](tailwind/base-styles-for-text-link.md)
- [Disable And Enable A Button](tailwind/disable-and-enable-a-button.md)
- [Specify Paths For Purging Unused CSS](tailwind/specify-paths-for-purging-unused-css.md)
- [Use Tailwind Typography Prose In Dark Mode](tailwind/use-tailwind-typography-prose-in-dark-mode.md)
### Taskfile
- [Create Interactive Picker For Set Of Subtasks](taskfile/create-interactive-picker-for-set-of-subtasks.md)
- [Run A Task If It Meets Criteria](taskfile/run-a-task-if-it-meets-criteria.md)
### tmux
- [Access Past Copy Buffer History](tmux/access-past-copy-buffer-history.md)
- [Add Bindings To Split Panes To Current Directory](tmux/add-bindings-to-split-panes-to-current-directory.md)
- [Adjusting Window Pane Size](tmux/adjusting-window-pane-size.md)
- [Break Current Pane Out To Separate Window](tmux/break-current-pane-out-to-separate-window.md)
- [Change Base Directory Of Existing Session](tmux/change-base-directory-of-existing-session.md)
@@ -1398,6 +1570,7 @@ _1534 TILs and counting..._
- [Reset An Option Back To Its Default Value](tmux/reset-an-option-back-to-its-default-value.md)
- [Set Environment Variables When Creating Session](tmux/set-environment-variables-when-creating-session.md)
- [Set Session Specific Environment Variables](tmux/set-session-specific-environment-variables.md)
- [Set Up Forwarding Prefix For Nested Session](tmux/set-up-forwarding-prefix-for-nested-session.md)
- [Show The Current Value For An Option](tmux/show-the-current-value-for-an-option.md)
- [Swap Split Panes](tmux/swap-split-panes.md)
- [Switch To A Specific Session And Window](tmux/switch-to-a-specific-session-and-window.md)
@@ -1431,6 +1604,7 @@ _1534 TILs and counting..._
### Unix
- [All The Environment Variables](unix/all-the-environment-variables.md)
- [Authorize A cURL Request](unix/authorize-a-curl-request.md)
- [Cat A File With Line Numbers](unix/cat-a-file-with-line-numbers.md)
- [Cat Files With Color Using Bat](unix/cat-files-with-color-using-bat.md)
- [Change Default Shell For A User](unix/change-default-shell-for-a-user.md)
@@ -1452,11 +1626,14 @@ _1534 TILs and counting..._
- [Count The Lines In A CSV Where A Column Is Empty](unix/count-the-lines-in-a-csv-where-a-column-is-empty.md)
- [Count The Number Of Matches In A Grep](unix/count-the-number-of-matches-in-a-grep.md)
- [Count The Number Of ripgrep Pattern Matches](unix/count-the-number-of-ripgrep-pattern-matches.md)
- [Count The Number Of Words On A Webpage](unix/count-the-number-of-words-on-a-webpage.md)
- [Create A File Descriptor with Process Substitution](unix/create-a-file-descriptor-with-process-substitution.md)
- [Create A Filename With The Current Date](unix/create-a-filename-with-the-current-date.md)
- [Create A Sequence Of Values With A Step](unix/create-a-sequence-of-values-with-a-step.md)
- [Curl With Cookies](unix/curl-with-cookies.md)
- [Curling For Headers](unix/curling-for-headers.md)
- [Curling With Basic Auth Credentials](unix/curling-with-basic-auth-credentials.md)
- [Determine ipv4 And ipv6 Public IP Addresses](unix/determine-ipv4-and-ipv6-public-ip-addresses.md)
- [Different Ways To Generate A v4 UUID](unix/different-ways-to-generate-a-v4-uuid.md)
- [Display All The Terminal Colors](unix/display-all-the-terminal-colors.md)
- [Display Free Disk Space](unix/display-free-disk-space.md)
@@ -1467,11 +1644,14 @@ _1534 TILs and counting..._
- [Enable Multi-Select Of Results With fzf](unix/enable-multi-select-of-results-with-fzf.md)
- [Exclude A Command From The ZSH History File](unix/exclude-a-command-from-the-zsh-history-file.md)
- [Exclude A Directory With Find](unix/exclude-a-directory-with-find.md)
- [Exclude A Specific File From fd Results](unix/exclude-a-specific-file-from-fd-results.md)
- [Exclude Certain Files From An rsync Run](unix/exclude-certain-files-from-an-rsync-run.md)
- [Figure Out The Week Of The Year From The Terminal](unix/figure-out-the-week-of-the-year-from-the-terminal.md)
- [File Type Info With File](unix/file-type-info-with-file.md)
- [Find All Files Matching A Name With fd](unix/find-all-files-matching-a-name-with-fd.md)
- [Find All Files With A Specific Extension With fd](unix/find-all-files-with-a-specific-extension-with-fd.md)
- [Find All Tool Version Files Containing Postgres](unix/find-all-tool-version-files-containing-postgres.md)
- [Find And Copy A Value From Large JSON Output](unix/find-and-copy-a-value-from-large-json-output.md)
- [Find Any Dotfiles That Modify Path Env Var](unix/find-any-dotfiles-that-modify-path-env-var.md)
- [Find A File Installed By Brew](unix/find-a-file-installed-by-brew.md)
- [Find Duplicate Lines In A File](unix/find-duplicate-lines-in-a-file.md)
@@ -1479,15 +1659,19 @@ _1534 TILs and counting..._
- [Find Newer Files](unix/find-newer-files.md)
- [Find Occurrences Of Multiple Values With Ripgrep](unix/find-occurrences-of-multiple-values-with-ripgrep.md)
- [Find Top-Level Directories Matching A Pattern](unix/find-top-level-directories-matching-a-pattern.md)
- [Fix Previous Command With fc](unix/fix-previous-command-with-fc.md)
- [Fix Shim Path After asdf Upgrade](unix/fix-shim-path-after-asdf-upgrade.md)
- [Fix Unlinked Node Binaries With asdf](unix/fix-unlinked-node-binaries-with-asdf.md)
- [Forward Multiple Ports Over SSH](unix/forward-multiple-ports-over-ssh.md)
- [Generate A SAML Key And Certificate Pair](unix/generate-a-saml-key-and-certificate-pair.md)
- [Generate A Sequence Of Numbered Items](unix/generate-a-sequence-of-numbered-items.md)
- [Generate Base64 Encoding Without Newlines](unix/generate-base64-encoding-without-newlines.md)
- [Generate Random 20-Character Hex String](unix/generate-random-20-character-hex-string.md)
- [Get A List Of Locales On Your System](unix/get-a-list-of-locales-on-your-system.md)
- [Get Matching Filenames As Output From Grep](unix/get-matching-filenames-as-output-from-grep.md)
- [Get The SHA256 Hash For A File](unix/get-the-sha256-hash-for-a-file.md)
- [Get The Unix Timestamp](unix/get-the-unix-timestamp.md)
- [Get Word Count For All Files In Git Repo](unix/get-word-count-for-all-files-in-git-repo.md)
- [Global Substitution On The Previous Command](unix/global-substitution-on-the-previous-command.md)
- [Globbing For All Directories In Zsh](unix/globbing-for-all-directories-in-zsh.md)
- [Globbing For Filenames In Zsh](unix/globbing-for-filenames-in-zsh.md)
@@ -1495,17 +1679,21 @@ _1534 TILs and counting..._
- [Grep For Files Without A Match](unix/grep-for-files-without-a-match.md)
- [Grep For Files With Multiple Matches](unix/grep-for-files-with-multiple-matches.md)
- [Grep For Multiple Patterns](unix/grep-for-multiple-patterns.md)
- [Have Script ShellCheck Itself When Executing](unix/have-script-shellcheck-itself-when-executing.md)
- [Hexdump A Compiled File](unix/hexdump-a-compiled-file.md)
- [Ignore A Directory During ripgrep Search](unix/ignore-a-directory-during-ripgrep-search.md)
- [Ignore The Alias When Running A Command](unix/ignore-the-alias-when-running-a-command.md)
- [Include Ignore Files In Ripgrep Search](unix/include-ignore-files-in-ripgrep-search.md)
- [Interactively Browse Available Node Versions](unix/interactively-browse-availabile-node-versions.md)
- [Interactively Switch asdf Package Versions](unix/interactively-switch-asdf-package-versions.md)
- [Interpret Cron Schedule From The CLI](unix/interpret-cron-schedule-from-the-cli.md)
- [Jump To The Ends Of Your Shell History](unix/jump-to-the-ends-of-your-shell-history.md)
- [Kill Everything Running On A Certain Port](unix/kill-everything-running-on-a-certain-port.md)
- [Killing A Frozen SSH Session](unix/killing-a-frozen-ssh-session.md)
- [Last Argument Of The Last Command](unix/last-argument-of-the-last-command.md)
- [Less With Style](unix/less-with-style.md)
- [Limit Protocols Used In A cURL Command](unix/limit-protocols-used-in-a-curl-command.md)
- [List All Fonts On Your Machine](unix/list-all-fonts-on-your-machine.md)
- [List All The Enabled ZSH Options](unix/list-all-the-enabled-zsh-options.md)
- [List All Users](unix/list-all-users.md)
- [List Files In A Single Column](unix/list-files-in-a-single-column.md)
@@ -1515,11 +1703,14 @@ _1534 TILs and counting..._
- [List Parent pid With ps](unix/list-parent-pid-with-ps.md)
- [List Stats For A File](unix/list-stats-for-a-file.md)
- [List The Available JDKs](unix/list-the-available-jdks.md)
- [List The PID And Name Of Current Shell Process](unix/list-the-pid-and-name-of-current-shell-process.md)
- [List The Stack Of Remembered Directories](unix/list-the-stack-of-remembered-directories.md)
- [List TXT DNS Records For A Domain](unix/list-txt-dns-records-for-a-domain.md)
- [Load Env Vars In Bash Script](unix/load-env-vars-in-bash-script.md)
- [Look Through All Files That Have Been Git Stashed](unix/look-through-all-files-that-have-been-git-stashed.md)
- [Make Direnv Less Noisy](unix/make-direnv-less-noisy.md)
- [Make Neovim The Default Way To View Man Pages](unix/make-neovim-the-default-way-to-view-man-pages.md)
- [Manually Pass Two Git Files To Delta](unix/manually-pass-two-git-files-to-delta.md)
- [Map A Domain To localhost](unix/map-a-domain-to-localhost.md)
- [Negative Look-Ahead Search With ripgrep](unix/negative-look-ahead-search-with-ripgrep.md)
- [Occupy A Local Port With Netcat](unix/occupy-a-local-port-with-netcat.md)
@@ -1536,6 +1727,7 @@ _1534 TILs and counting..._
- [Produce A Lowercase V4 UUID](unix/produce-a-lowercase-v4-uuid.md)
- [Provide A Fallback Value For Unset Parameter](unix/provide-a-fallback-value-for-unset-parameter.md)
- [Remove A Directory Called `-p`](unix/remove-a-directory-called-dash-p.md)
- [Rename A Bunch Of Files By Constructing mv Commands](unix/rename-a-bunch-of-files-by-constructing-mv-commands.md)
- [Repeat Yourself](unix/repeat-yourself.md)
- [Replace Pattern Across Many Files In A Project](unix/replace-pattern-across-many-files-in-a-project.md)
- [Run A Command Repeatedly Several Times](unix/run-a-command-repeatedly-several-times.md)
@@ -1547,7 +1739,9 @@ _1534 TILs and counting..._
- [Search History](unix/search-history.md)
- [Search Man Page Descriptions](unix/search-man-page-descriptions.md)
- [Securely Remove Files](unix/securely-remove-files.md)
- [See Where asdf Gets Current Tool Version](unix/see-where-asdf-gets-current-tool-version.md)
- [Set The asdf Package Version For A Single Shell](unix/set-the-asdf-package-version-for-a-single-shell.md)
- [Shorten SSH Commands With Aliases](unix/shorten-ssh-commands-with-aliases.md)
- [Show A File Preview When Searching With FZF](unix/show-a-file-preview-when-searching-with-fzf.md)
- [Show Disk Usage For The Current Directory](unix/show-disk-usage-for-the-current-directory.md)
- [Show The Size Of Everything In A Directory](unix/show-the-size-of-everything-in-a-directory.md)
@@ -1559,6 +1753,7 @@ _1534 TILs and counting..._
- [Switch Versions of a Brew Formula](unix/switch-versions-of-a-brew-formula.md)
- [Tell direnv To Load The Env File](unix/tell-direnv-to-load-the-env-file.md)
- [Touch Access And Modify Times Individually](unix/touch-access-and-modify-times-individually.md)
- [Transform Text To Lowercase](unix/transform-text-to-lowercase.md)
- [Type Fewer Paths With Brace Expansion](unix/type-fewer-paths-with-brace-expansion.md)
- [Undo Changes Made To Current Terminal Prompt](unix/undo-changes-made-to-current-terminal-prompt.md)
- [Undo Some Command Line Editing](unix/undo-some-command-line-editing.md)
@@ -1600,6 +1795,7 @@ _1534 TILs and counting..._
- [Breaking The Undo Sequence](vim/breaking-the-undo-sequence.md)
- [Buffer Time Travel](vim/buffer-time-travel.md)
- [Build And Install A Go Program](vim/build-and-install-a-go-program.md)
- [Bypass On-Save Tooling When Writing File](vim/bypass-on-save-tooling-when-writing-file.md)
- [Case-Aware Substitution With vim-abolish](vim/case-aware-substitution-with-vim-abolish.md)
- [Case-Insensitive Substitution](vim/case-insensitive-substitution.md)
- [Center The Cursor](vim/center-the-cursor.md)
@@ -1640,6 +1836,7 @@ _1534 TILs and counting..._
- [Generate and Edit Rails Migration](vim/generate-and-edit-rails-migration.md)
- [Get The pid Of The Session](vim/get-the-pid-of-the-session.md)
- [Go Back To The Previous Window](vim/go-back-to-the-previous-window.md)
- [Go To Beginning And End Of Line](vim/go-to-beginning-and-end-of-line.md)
- [Go To File With Line Number](vim/go-to-file-with-line-number.md)
- [Grepping Through The Vim Help Files](vim/grepping-through-the-vim-help-files.md)
- [Head of File Name](vim/head-of-file-name.md)
@@ -1701,6 +1898,7 @@ _1534 TILs and counting..._
- [Replace A Character](vim/replace-a-character.md)
- [Reset Target tslime Pane](vim/reset-target-tslime-pane.md)
- [Reverse A Group Of Lines](vim/reverse-a-group-of-lines.md)
- [Reword A Commit Message With Fugitive](vim/reword-a-commit-message-with-fugitive.md)
- [Rotate Everything By 13 Letters](vim/rotate-everything-by-13-letters.md)
- [Rotate The Orientation Of Split Windows](vim/rotate-the-orientation-of-split-windows.md)
- [Running Bundle With vim-bundler](vim/running-bundle-with-vim-bundler.md)
@@ -1749,6 +1947,7 @@ _1534 TILs and counting..._
- [Find The Location Of User Settings JSON File](vscode/find-the-location-of-user-settings-json-file.md)
- [Jump To Problems In The Current File](vscode/jump-to-problems-in-the-current-file.md)
- [Open An Integrated Terminal Window](vscode/open-an-integrated-terminal-window.md)
- [Open File On Remote Like GitHub](vscode/open-file-on-remote-like-github.md)
- [Pop Open The Quick Fix Window](vscode/pop-open-the-quick-fix-window.md)
- [Step Through Project-Wide Search Results](vscode/step-through-project-wide-search-results.md)
- [Synchronize Vim Clipboard With System Clipboard](vscode/synchronize-vim-clipboard-with-system-clipboard.md)
@@ -1770,11 +1969,15 @@ _1534 TILs and counting..._
- [Add Subtitles To Existing Mux Video Asset](workflow/add-subtitles-to-existing-mux-video-asset.md)
- [Access 1Password Credential From CLI](workflow/access-1password-credential-from-cli.md)
- [Allow Key-Repeating With Cursor](workflow/allow-key-repeating-with-cursor.md)
- [Break Justfile Into Separate Hidden Steps](workflow/break-justfile-into-separate-hidden-steps.md)
- [Change Window Name In iTerm](workflow/change-window-name-in-iterm.md)
- [Configure Email Redirect With Cloudflare](workflow/configure-email-redirect-with-cloudflare.md)
- [Control Media With Drop Keyboard](workflow/control-media-with-drop-keyboard.md)
- [Convert An ePub Document To PDF On Mac](workflow/convert-an-epub-document-to-pdf-on-mac.md)
- [Create A Local Sanity Dataset Backup](workflow/create-a-local-sanity-dataset-backup.md)
- [Create A Public URL For A Local Server](workflow/create-a-public-url-for-a-local-server.md)
- [Create Todo Items In Logseq](workflow/create-todo-items-in-logseq.md)
- [Do Project Time Tracking From The CLI](workflow/do-project-time-tracking-from-the-cli.md)
- [Enable Dev Tools For Safari](workflow/enable-dev-tools-for-safari.md)
- [Forward Stripe Events To Local Server](workflow/forward-stripe-events-to-local-server.md)
- [Get URL For GitHub User Profile Photo](workflow/get-url-for-github-user-profile-photo.md)
@@ -1782,13 +1985,18 @@ _1534 TILs and counting..._
- [Import A Github Project Into CodeSandbox](workflow/import-a-github-project-into-codesandbox.md)
- [Interactively Kill A Process With fkill](workflow/interactively-kill-a-process-with-fkill.md)
- [Open Slack's Keyboard Shortcuts Reference Panel](workflow/open-slacks-keyboard-shortcuts-reference-panel.md)
- [Pop Videos Out As Picture-in-Picture](workflow/pop-videos-out-as-picture-in-picture.md)
- [Prune The Excess From node_modules](workflow/prune-the-excess-from-node-modules.md)
- [Rotate An Image To Be Oriented Upright](workflow/rotate-an-image-to-be-oriented-upright.md)
- [See Overlaps For A Set Of Time Zones](workflow/see-overlaps-for-a-set-of-time-zones.md)
- [Send A Message To A Discord Channel](workflow/send-a-message-to-a-discord-channel.md)
- [Send A PDF To Your Kindle](workflow/send-a-pdf-to-your-kindle.md)
- [Set Recurring Reminders In Slack](workflow/set-recurring-reminders-in-slack.md)
- [Show Linting Errors In Zed](workflow/show-linting-errors-in-zed.md)
- [Temporarily Hide CleanShot X Capture Previews](workflow/temporarily-hide-cleanshot-x-capture-previews.md)
- [Toggle Between Stories In Storybook](workflow/toggle-between-stories-in-storybook.md)
- [Update asdf Plugins With Latest Package Versions](workflow/update-asdf-plugins-with-latest-package-versions.md)
- [View A Nicely-Formatted CSV In Terminal](workflow/view-a-nicely-formatted-csv-in-terminal.md)
- [View The PR For The Current GitHub Branch](workflow/view-the-pr-for-the-current-github-branch.md)
### XState
@@ -1819,7 +2027,9 @@ _1534 TILs and counting..._
### Zsh
- [A Better Way To Reload ZSH Configuration](zsh/a-better-way-to-reload-zsh-configuration.md)
- [Add To The Path Via Path Array](zsh/add-to-the-path-via-path-array.md)
- [Create And Jump Into A Directory](zsh/create-and-jump-into-a-directory.md)
- [Link A Scalar To An Array](zsh/link-a-scalar-to-an-array.md)
- [Use A Space To Exclude Command From History](zsh/use-a-space-to-exclude-command-from-history.md)
@@ -1831,6 +2041,10 @@ current number of TILs and display the result in the command tray.
## About
I've written more about how this repo came to be in [How I Built a Learning
Machine](https://dev.to/jbranchaud/how-i-built-a-learning-machine-45k9) and [A
Decade of TILs](https://www.visualmode.dev/a-decade-of-tils).
I shamelessly stole this idea from
[thoughtbot/til](https://github.com/thoughtbot/til).
@@ -1838,11 +2052,11 @@ I shamelessly stole this idea from
* [Today I Learned by Hashrocket](https://til.hashrocket.com)
* [jwworth/til](https://github.com/jwworth/til)
* [thoughtbot/til](https://github.com/thoughtbot/til)
* [til.simonwillison.net](https://til.simonwillison.net/)
## License
&copy; 2015-2022 Josh Branchaud
&copy; 2015-2025 Josh Branchaud
This repository is licensed under the MIT license. See `LICENSE` for
details.

79
Taskfile.yml Normal file
View File

@@ -0,0 +1,79 @@
version: '3'
vars:
NOTES_DIR: notes
NOTES_FILE: '{{.NOTES_DIR}}/NOTES.md'
EDITOR: '{{.EDITOR | default "nvim"}}'
tasks:
default:
desc: Show available commands
cmds:
- task --list
notes:
desc: Interactive picker for notes tasks
cmds:
- |
TASK=$(task --list | grep "^\* notes:" | sed 's/^\* notes://' | sed 's/\s\+/ - /' | fzf --prompt="Select notes task: " --height=40% --reverse) || true
if [ -n "$TASK" ]; then
TASK_NAME=$(echo "$TASK" | awk '{print $1}' | sed 's/:$//')
task notes:$TASK_NAME
fi
interactive: true
silent: true
notes:edit:
desc: All-in-one edit, commit, and push notes
cmds:
- task notes:open
- task notes:push
notes:sync:
desc: Sync latest changes from the notes submodule
cmds:
- git submodule update --remote {{.NOTES_DIR}}
- cd {{.NOTES_DIR}} && git checkout main
silent: false
notes:open:
desc: Opens NOTES.md (syncs latest changes first) in default editor
deps: [notes:sync]
cmds:
- $EDITOR {{.NOTES_FILE}}
interactive: true
notes:push:
desc: Commit and push changes to notes submodule
dir: '{{.NOTES_DIR}}'
cmds:
- git add NOTES.md
- git commit -m "Update notes - $(date '+%Y-%m-%d %H:%M')"
- git pull --rebase
- git push
status:
- git diff --exit-code NOTES.md
silent: false
notes:status:
desc: Check status of notes submodule
dir: '{{.NOTES_DIR}}'
cmds:
- git status
notes:pull:
desc: Pull latest changes (alias for sync)
cmds:
- task notes:sync
notes:diff:
desc: Show uncommitted changes in notes
dir: '{{.NOTES_DIR}}'
cmds:
- git diff NOTES.md
notes:log:
desc: Show recent commit history for notes
dir: '{{.NOTES_DIR}}'
cmds:
- git log --oneline -10

View File

@@ -0,0 +1,30 @@
# AWS CLI Requires Groff Executable
I have the AWS CLI installed on this machine, but when I went to run certain
commands like `aws logs tail my_log_group` or even `aws logs tail help`, I'd
get the following error:
```
$ aws logs tail help
Could not find executable named 'groff'
```
This may only be an issue on MacOS Ventura for older versions of the CLI, per
[this PR](https://github.com/aws/aws-cli/pull/7413):
> The CLI's help commands are currently broken on macOS Ventura because Ventura has replaced groff with mandoc. This PR fixes the issue by falling back on mandoc if groff doesn't exist in the path.
There are two ways of dealing with this. One would be to install the missing
dependency, [`groff`](https://www.gnu.org/software/groff/):
```bash
$ brew install groff
```
The other is to update the AWS CLI to one that falls back to `mandoc`.
Depending on how you originally installed the AWS CLI, you can either [follow
their official install/upgrade
instructions](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html),
`pip install --upgrade awscli`, or upgrade view homebrew (`brew upgrade
awscli`).

View File

@@ -0,0 +1,46 @@
# Find And Follow Server Logs
Let's say you are authenticated with the AWS CLI and have the appropriate
CloudWatch permissions. You have a few services running in production with
associated logs. One of those is a Rails server.
We want to run `aws logs tail`, but first we check how that command works.
```bash
$ aws logs tail help
```
We see a bunch of options, but the only required one is `group_name` ("The name
of the CloudWatch Logs group."). We may also notice the `--follow` flag which
we'll want to use as well to keep incoming logs flowing.
We need to determine the log group name for the Rails server. We can do that
from the CLI as well (no need to dig into the web UI).
```bash
$ aws logs describe-log-groups
{
"logGroups": [
{
"logGroupName": "/aws/codebuild/fc-rails-app-abcefg-123456",
"creationTime": 1739476650823,
"metricFilterCount": 0,
"arn": "arn:aws:logs:us-east-2:123456789:log-group:/aws/codebuild/fc-rails-app-abcefg-123456:*",
"storedBytes": 65617,
"logGroupClass": "STANDARD",
"logGroupArn": "arn:aws:logs:us-east-2:123456789:log-group:/aws/codebuild/fc-rails-app-abcefg-123456"
},
...
]
}
```
Because the group name is descriptive enough, we can find the log group we are
interested in: `/aws/codebuild/fc-rails-app-abcefg-123456`.
Now we know what we want to `tail`.
```bash
$ aws logs tail /aws/codebuild/fc-rails-app-abcefg-123456 --follow
```

View File

@@ -0,0 +1,29 @@
# List RDS Snapshots With Matching Identifier Prefix
I'm working on a script that manually creates a snapshot which it will then
restore to a temporary database that I can scrub and dump. The snapshots that
this script takes are _manual_ and they are named with identifiers that have a
defining prefix (`dev-snapshot-`). Besides the few snapshots created by this
script, there are tons of automated snapshots that RDS creates for
backup/recovery purposes.
I want to list any snapshots that have been created by the script. I can do
this with the `describe-db-snapshots` command and some filters.
```bash
$ aws rds describe-db-snapshots \
--snapshot-type manual \
--query "DBSnapshots[?starts_with(DBSnapshotIdentifier, 'dev-snapshot-')].DBSnapshotIdentifier" \
--no-cli-pager
[
"dev-snapshot-20250327-155355"
]
```
There are two key pieces. The `--snapshot-type manual` filter excludes all
those automated snapshots. The `--query` both filters to any snapshots whose
identifier `?starts_with` the prefix `dev-snapshot-` and then refines the
output to just the `DBSnapshotIdentifier` instead of the entire JSON object.
[source](https://docs.aws.amazon.com/cli/latest/reference/rds/describe-db-snapshots.html)

View File

@@ -0,0 +1,49 @@
# Output CLI Results In Different Formats
The AWS CLI can output the results of commands in three different formats.
- Text
- JSON
- Table
The _default_ output format for my AWS CLI is currently configured to `json`.
```bash
$ aws configure get output
json
```
I can either accept the default or I can override it with the `--output` flag.
```bash
$ aws rds describe-db-instances \
--query 'DBInstances[*].Endpoint' \
--no-cli-pager
[
{
"Address": "fc-database-abcefg-ab1c23de.asdfgh4zxcvb.us-east-2.rds.amazonaws.com",
"Port": 5432,
"HostedZoneId": "A1BCDE2FG345H6"
}
]
$ aws rds describe-db-instances \
--query 'DBInstances[*].Endpoint' \
--no-cli-pager \
--output table
----------------------------------------------------------------------------------------------------
| DescribeDBInstances |
+-----------------------------------------------------------------------+-----------------+--------+
| Address | HostedZoneId | Port |
+-----------------------------------------------------------------------+-----------------+--------+
| fc-database-abcefg-ab1c23de.asdfgh4zxcvb.us-east-2.rds.amazonaws.com | A1BCDE2FG345H6 | 5432 |
+-----------------------------------------------------------------------+-----------------+--------+
$ aws rds describe-db-instances \
--query 'DBInstances[*].Endpoint' \
--no-cli-pager \
--output text
fc-database-abcefg-ab1c23de.asdfgh4zxcvb.us-east-2.rds.amazonaws.com A1BCDE2FG345H6 5432
```
[source](https://docs.aws.amazon.com/cli/v1/userguide/cli-usage-output-format.html)

View File

@@ -0,0 +1,50 @@
# SSH Into An ECS Container
In [Connect To Production Rails Console on AWS /
Flightcontrol](https://www.visualmode.dev/connect-to-production-rails-console-aws-flightcontrol),
I went into full detail about how to access `rails console` for a production
Rails app running in an ECS container.
A big part of that process was establishing an SSH connection to the ECS container.
To do that, I need to know my region, container ID, and task ID. I can get the
first two by listing my clusters and finding the cluster/container that houses
the Rails app.
```bash
$ aws ecs list-clusters
{
"clusterArns": [
"arn:aws:ecs:us-east-2:123:cluster/rails-app-abc123"
]
}
```
The region then is `us-east-2` and the container ID is `rails-app-abc123`.
I can use that to find the task ID:
```bash
$ aws ecs list-tasks --region us-east-2 --cluster rails-app-abc123
{
"taskArns": [
"arn:aws:ecs:us-east-2:123:task/rails-app-abc123/8526b3191d103bb1ff90c65a655ad004"
]
}
```
The task ID is the final portion of the URL:
`8526b3191d103bb1ff90c65a655ad004`.
Putting this all together I can SSH into the ECS container with a bash profile
like so:
```bash
$ aws ecs execute-command \
--region us-east-2 \
--cluster rails-app-abc123 \
--container rails-app-abc123 \
--task 8526b3191d103bb1ff90c65a655ad004 \
--interactive \
--command "/bin/bash"
```

View File

@@ -0,0 +1,38 @@
# Turn Off Output Pager For A Command
It is not uncommon for an AWS CLI command to return a ton of output. When that
happens, it is nice that the results end up in pager program (like `less`)
where you can search and review them, copy a value of interest, and then exit.
The pager prevents that wall of output from cluttering your terminal history.
However, sometimes I am running a command that I know is going to return a
small result. I'd rather have the results go to stdout where I can see them in
the terminal history rather than to an ephemeral pager.
For that situation I can tack on the `--no-cli-pager` flag.
```bash
$ aws rds describe-db-instances \
--query 'DBInstances[*].EngineVersion' \
--output json \
--no-cli-pager
[
"13.15",
"16.8"
]
```
Here I've asked the AWS CLI to tell me the engine versions of all my RDS
Postgres databases. Because I know the results are only going to include a
couple results for my couple of DBs, I'd like to skip the pager —
`--no-cli-pager`.
Though I think it is better to do this on a case by case basis, it is also
possible to turn off the pager via the CLI configuration file.
```bash
$ aws configure set cli_pager ""
```
[source](https://docs.aws.amazon.com/cli/latest/userguide/cli-usage-pagination.html#cli-usage-pagination-clientside)

View File

@@ -0,0 +1,37 @@
# Use Specific AWS Profile With CLI
I have multiple AWS profiles authenticated with the AWS CLI. For some projects
I need to use the `default` one and for others I need to use the other.
First, I can list the available profiles like so:
```bash
$ aws configure list-profiles
default
dev-my-app
```
For one-off commands I can specify the profile for any AWS CLI command using
the `--profile` flag.
```bash
$ aws ecs list-clusters --profile josh-visualmode
```
However, I don't want to have to specify that flag every time when I'm working
on a specific project. Instead I can specify the profile with an environment
variable. The [`direnv`](https://direnv.net/) tool is a great way to do this on
a per-project / per-directory basis.
I can create or update the `.envrc` file (assuming I have `direnv` installed)
adding the following line (and re-allowing the changed file):
```
# .envrc
export AWS_PROFILE=dev-my-app
```
Now, any AWS command I issue from that directory or its subdirectories will use
that profile by default.
[source](https://docs.aws.amazon.com/cli/v1/userguide/cli-configure-files.html#cli-configure-files-using-profiles)

View File

@@ -0,0 +1,40 @@
# Clean Up Your Brew Installations
Over time as you upgrade brew-installed programs and make changes to your
`Brewfile`, your machine will have artifacts left behind that you no longer
need.
Periodically, it is good to clean things up.
First, you can get a summary of stale and outdated files that brew has
installed. Use the `--dry-run` flag.
```bash
$ brew cleanup --dry-run
```
If you feel good about what you see in the output, then give things a clean.
```bash
$ brew cleanup
```
Second, if you are using a `Brewfile` to manage what `brew` installs, then you
can instruct `brew` to uninstall any dependencies that aren't specified in that
file.
By default it operates as a dry run and the `--force` flag will be needed to
actually do the cleanup. And specify the filename if it doesn't match the
default of `Brewfile`.
```bash
$ brew bundle cleanup --file=Brewfile.personal
```
If the output looks good, then force the cleanup:
```bash
$ brew bundle cleanup --force --file=Brewfile.personal
```
See `brew cleanup --help` and `brew bundle --help` for more details.

View File

@@ -0,0 +1,27 @@
# Install Go Packages In Brewfile
Typically my `Brewfile` is only full of `brew` and `cask` directives. That's
starting to change now that `brew` supports installing Go packages listed in the
`Brewfile`.
Use the `go` directive and the URL to the hosted Go package.
Here is an example of a `Brewfile` that includes a `cask`, `brew`, and `go`
directive.
```
# screen resolution tool
cask "betterdisplay"
# Mac keychain management, gpg key
brew "pinentry-mac"
# Sanitized production Postgres dumps
go "github.com/jackc/pg_partialcopy"
```
I've recently added the exact package from above to my [`dotfiles`
repo](https://github.com/jbranchaud/dotfiles/commit/e83e9d19504f0e2f95eba33123f907f999bf865e).
Here is the [PR to `brew`](https://github.com/Homebrew/brew/pull/20798) where
this functionality was added back in October of 2025.

View File

@@ -0,0 +1,14 @@
# Open Current Tab In New Window With Vimium
Sometime I have a busy Chrome window going with a bunch of tabs open for
various lines of work as well as a number of tabs that I've neglected to close.
I then open a new tab, find something useful, and realize I'm at a "branching
point". I'm about to start in on a specific chunk of work that will probably
involve opening several more tabs and switch back and forth between some
dashboards. I want to start all of this from a fresh slate -- or at least from
a fresh Chrome window.
With [Vimium](https://github.com/philc/vimium), I can hit `W` (`Shift-w`) to
have the current tab move from the current window to a new window. The original
window, minus that one tab, will be left as is so that I can go back to it as
needed.

View File

@@ -0,0 +1,22 @@
# Search Tabs With The Vimium Vomnibar
If you use Chrome like I do, then you eventually end up with several windows
with dozens if not 100+ tabs open. It can start to get tedius with that many
tabs to find and navigate to a given tab. Someone might suggest closing a few
dozen tabs as a solution to this predicament. However, Vimium offers a solution
that doesn't require I [_kill my
darlings_](https://en.wiktionary.org/wiki/kill_one%27s_darlings).
The Vomnibar, a Vimium-powered search bar, can be summoned with `T` to only
search through open tabs.
When I hit `T`, I see a text area (for refining the search) and then a bunch of
entries populate below that which I immediately recognize as many of those tabs
that I'm going to get back to one of these days.
To narrow down to the specific thing I'm looking for, I type something into the
input. Then I arrow to the result I'm looking for and hit enter. And I'm
transported to that tab.
If I don't like where I ended up, I can also go back to the tab I had been on
with `^`.

View File

@@ -0,0 +1,18 @@
# Monitor Usage Limits From CLI
When I first started using Claude Code enough to push the usage limits, I would
periodically switch over to the browser to check
`https://claude.ai/settings/usage` to see how close I was getting. That page
would tell me what percentage of my allotted usage I had consumed so far for the
current 5-hour session and then how long until that 5-hour usage window resets.
This can also be viewed directly in Claude Code for the CLI.
First, run the `/status` slash command and then _tab_ over to the _Usage_
section. There you will see the same details as in the web view.
I'm also learned, as I write this, that you can go directly to the _Usage_
section by typing the `/usage` slash command.
See [the docs](https://code.claude.com/docs/en/slash-commands) for a listing of
all slash commands.

View File

@@ -0,0 +1,15 @@
# Open Current Prompt In Default Editor
[Claude Code](https://www.claude.com/product/claude-code) gives you a single
line to write a prompt. You can write and write as much as you want, but it will
all be on that single line. And avoid accidentally hitting 'Enter' before you're
done.
I found myself wanting to space out my thoughts, create a code block as part of
a prompt, and generally have a scratch pad instead of just a text box. By
hitting `ctrl-g`, I can move the current prompt into my default editor (in my
case, `nvim`). From there I can continue to write, edit, and format with all the
affordances of an editor.
Once I'm done crafting the prompt, I can save (e.g. `:wq`) and Claude Code will
be primed with that text. I can then hit 'Enter' to let `claude` do its thing.

View File

@@ -0,0 +1,29 @@
# Filter Blur Requires Expensive Calculation
I had [a
page](https://www.visualmode.dev/connect-to-production-rails-console-aws-flightcontrol)
on my blog that was experiencing some odd rendering behavior. The issue was
manifesting a couple ways.
- Resizing and scrolling were janky and causing entire page layers to re-render
causing the page to flash in and out.
- Sometimes entire layer chunks would fail to paint leaving a white block
missing from the page.
The issue was occurring with and without JavaScript turned on for a
statically-built page. I suspected that some aspect of the CSS was at fault.
I was going back and forth with Dillon Hafer about what the issue could be and
he wondered, "could it be the backdrop-blur class from tailwind?". I tried
removing that class and the responsiveness of the page immediately improved.
The [`filter:
blur`](https://developer.mozilla.org/en-US/docs/Web/CSS/filter-function/blur)
and [`backdrop-filter:
blur`](https://developer.mozilla.org/en-US/docs/Web/CSS/backdrop-filter) both
use an expensive [Gaussian blur](https://en.wikipedia.org/wiki/Gaussian_blur)
calculation. One of these on a modern machine and browser probably won't have a
noticable impact. However, a bunch of them, as in the case of my page with a
recurring component, can have quite the performance hit.
[source](https://github.com/tailwindlabs/tailwindcss/issues/15256)

View File

@@ -0,0 +1,29 @@
# Prevent Invisible Elements From Being Clicked
I have a nav element that when clicked reveals a custom drop-down menu. It
reveals it using CSS transitions and transformations (`opacity` and `scale`).
When the nav element is clicked again, the reverse of these transformations is
applied to "hide" the menu. This gives a nice visual effect.
It only makes the menu invisible and doesn't actually make it go away. That
means that menu could be invisible, but hovering over the top of a button on
the screen. The button cannot be clicked now because the menu is intercepting
that [_pointer
event_](https://developer.mozilla.org/en-US/docs/Web/CSS/pointer-events).
The fix is to apply CSS (or a class) when the drop-down menu is closed that
tells it to ignore _pointer events_.
```css
.pointer-events-none {
pointer-events: none;
}
```
This is more of less what [the `pointer-events-none` TailwindCSS
utility](https://tailwindcss.com/docs/pointer-events) looks like.
This class is applied by default to the drop-down menu. Then when the nav item
is clicked, some JavaScript removes that class at the same moment that the menu
is visually appearing. When a menu item is selected or the menu otherwise
closed, it transitions away and the `pointer-events-none` class is reapplied.

View File

@@ -0,0 +1,32 @@
# Allow Cursor To Be Launched From CLI
It is nice to be able to open Cursor for a specific project directly from the
terminal like so:
```bash
$ cd ~/dev/my/project
$ cursor .
```
For the `cursor` launcher binary to be available like that, we have to find it
and add it to the path.
It is probably located in the `/Applications` folder and within that nested down
a couple directories is a `bin` directory that contains the binary we're looking
for.
```bash
ls /Applications/Cursor.app/Contents/Resources/app/bin
 bin/
├──  code*
├──  cursor*
└──  cursor-tunnel*
```
The `cursor` binary is what we want, so let's add that to our path. In my case,
I'll add this to my `~/.zshrc` file.
```bash
export PATH="/Applications/Cursor.app/Contents/Resources/app/bin:$PATH"
```

View File

@@ -0,0 +1,28 @@
# Default Rails Deploy Script On Hatchbox
I deployed a Rails app to [Hatchbox](https://hatchbox.io) recently. When
following along in the log during a deploy, I can see most of what is happening
as part of the deploy. Though it is too verbose to look through every line. I'd
rather see the contents of the deploy script.
I did quite a bit of digging around while SSH'd into my hatchbox server, but I
couldn't find if or where that file might be stored.
Instead, there is a [_Help Center_
article](https://hatchbox.relationkit.io/articles/55-what-is-the-default-rails-deploy-script)
where Chris Oliver shares what is in the script.
```bash
bundle install -j $(nproc)
yarn install
bundle exec rails assets:precompile
[[ -n "${CRON}" ]] && bundle exec rails db:migrate
```
It does a parallelized `bundle install`, then a `yarn install` (make sure your
project is using `yarn.lock`), Rails asset precompilation, and then if `CRON`
is set (Cron role is available by checking _Cron_ under _Server
Responsibilities_ for your Hatchbox server), it will run Rails migrations.
From app settings, the deploy script can be overridden, or pre- and post-deploy
steps can be added.

View File

@@ -0,0 +1,44 @@
# Hatchbox Exports Env Vars With asdf
When you add env vars through the [Hatchbox](https://hatchbox.io/) UI, they get
exported to the environment of the asdf-shimmed processes. This is handled by
the [`asdf-vars` plugin](https://github.com/excid3/asdf-vars). That plugin
looks for `.asdf-vars` in the current chain of directories.
I can see there are many `.asdf-vars` files:
```bash
$ find . -name ".asdf-vars" -type f
./.asdf-vars
./my-app/.asdf-vars
./my-app/releases/20250120195106/.asdf-vars
./my-app/releases/20250121041054/.asdf-vars
```
And it is the one in my app's directory that contains the env vars that I set
in the UI.
```bash
$ cat my-app/.asdf-vars
BUNDLE_WITHOUT=development:test
DATABASE_URL=postgresql://user_123:123456789012345@10.0.1.1/my_app_db
PORT=9000
RACK_ENV=production
RAILS_ENV=production
RAILS_LOG_TO_STDOUT=true
RAILS_MASTER_KEY=abc123
SECRET_KEY_BASE=abc123efg456
```
When I run a shimmed process like `ruby`, those env vars are loaded into the
process's environment.
```bash
$ cd my-app/current
$ which ruby
/home/deploy/.asdf/shims/ruby
$ ruby -e "puts ENV['DATABASE_URL']"
postgresql://user_123:123456789012345@10.0.1.1/my_app_db
```
[source](https://www.visualmode.dev/hatchbox-manages-env-vars-with-asdf)

View File

@@ -0,0 +1,24 @@
# Set Up Domain For Hatchbox Rails App
When we deploy a Rails app with [Hatchbox](https://hatchbox.io), we are given
an internal URL for publicly accessing our app. It is something like
`https://123abc.hatchboxapp.com`. That's useful as we are getting things up and
running, but eventually we want to point our own domain at the app.
The first step is to tell Hatchbox what domain we are going to use.
From our app's _Domain & SSL_ page we can enter a domain into the _Add A
Domain_ input. For instance, I have the
[visualmode.dev](https://visualmode.dev) domain and I want the
[still.visualmode.dev](https://still.visualmode.dev) subdomain pointing at my
Rails app. I submit the full name `still.visualmode.dev` and I get an _A
Record_ ipv4 address (e.g. `23.12.234.82`).
The second step is to configure a DNS record with our domain registrar.
From the DNS settings of our registrar (e.g. Cloudflare) we can add an _A
Record_ where we specify the name (e.g. `still`) and then include the ipv4
address provided by Hatchbox. We can save this and wait a minute for it to
propagate.
And soon enough we can visit our Rails app at the custom domain.

View File

@@ -0,0 +1,28 @@
# Check Postgres Version Running In Docker Container
I have a docker container that I'm using to run a PostgreSQL development
database on my local machine. It was a while ago when I set it up, so I can't
remember specifically which major version of PostgreSQL I am using.
I use `docker ps` to list the names of each container.
```bash
$ docker ps --format "{{.Names}}"
still-postgres-1
better_reads-postgres-1
```
I grab the one I am interested in. In this case, that is `still-postgres-1`.
Then I can execute a `select version()` statement with `psql` against the
container with that name like so:
```bash
$ docker exec still-postgres-1 psql -U postgres -c "select version()";
version
---------------------------------------------------------------------------------------------------------------------
PostgreSQL 16.2 (Debian 16.2-1.pgdg120+2) on x86_64-pc-linux-gnu, compiled by gcc (Debian 12.2.0-14) 12.2.0, 64-bit
(1 row)
```
And there I have it. I'm running Postgres v16 in this container.

View File

@@ -0,0 +1,53 @@
# Prevent Containers From Running On Startup
I have a bunch of docker containers managed by Docker Desktop. Some are related
to projects I'm actively working on. Whereas many others are inactive projects.
When I restart my machine, regardless of which containers I had running or
turned off, several of them are booted into a running state on startup. This is
becaue their restart policy is set to `always`. That's fine for the project I'm
actively working on, but the others I would like to be _off_ by default.
I need to update each of their restart policies from `always` to `no`.
First, I need to figure out their container IDs:
```bash
$ docker ps --all
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
eb7b40aeba2d postgres:latest "docker-entrypoint.s…" 3 months ago Up 11 minutes 0.0.0.0:9875->5432/tcp still-postgres-1
eb9ab2213f2b postgres:latest "docker-entrypoint.s…" 3 months ago Exited (0) 11 minutes ago next-drizzle-migration-repro-app-postgres-1
ba792e185734 postgres:latest "docker-entrypoint.s…" 4 months ago Up 11 minutes 0.0.0.0:9876->5432/tcp better_reads-postgres-1
3139f9beae76 postgres:latest "docker-entrypoint.s…" 9 months ago Exited (128) 7 months ago basic-next-prisma-postgres-1
```
Referencing the `CONTAINER ID` and `NAMES` columns, I'm able to then inspect
each container and see the current `RestartPolicy`:
```bash
$ docker inspect eb9ab2213f2b | grep -A3 RestartPolicy
"RestartPolicy": {
"Name": "always",
"MaximumRetryCount": 0
},
```
I can then update the `RestartPolicy` to be `no`:
```bash
$ docker update --restart no eb9ab2213f2b
```
Inpsecting that container again, I can see the updated policy:
```bash
$ docker inspect eb9ab2213f2b | grep -A3 RestartPolicy
"RestartPolicy": {
"Name": "no",
"MaximumRetryCount": 0
},
```
Rinse and repeat for each of the offending containers.
[source](https://stackoverflow.com/questions/45423334/stopping-docker-containers-from-being-there-on-startup)

View File

@@ -0,0 +1,42 @@
# Run SQL Script Against Postgres Container
I've been using dockerized Postgres for local development with several projects
lately. This is typically with framework tooling (like Rails) where schema
migrations and query execution are handled by the tooling using the specified
connection parameters.
However, I was experimenting with and iterating on some Postgres functions
outside of any framework tooling. I needed a way to run the SQL script that
(re)creates the function via `psql` on the docker container.
With a local, non-containerized Postgres instance, I'd redirect the file to
`psql` like so:
```bash
$ psql -U postgres -d postgres < experimental-functions.sql
```
When I tried doing this with `docker exec` though, it was silently failing /
doing nothing. As far as I can tell, there was a mismatch with redirection
handling across the bounds of the container.
To get around this, I first copy the file into the `/tmp` directory on the
container:
```bash
$ docker cp experimental-functions.sql still-postgres-1:/tmp/experimental-functions.sql
```
Then the `psql` command that docker executes can be pointed directly at a
local-to-it SQL file.
```bash
$ docker exec still-postgres-1 psql \
-U postgres \
-d postgres \
-f /tmp/experimental-functions.sql
```
There are probably other ways to handle this, but I got into a nice rhythm with
this file full of `create or replace function ...` definitions where I could
modify, copy over, execute, run some SQL to verify, and repeat.

4
dprint.json Normal file
View File

@@ -0,0 +1,4 @@
{
"excludes": ["README.md"],
"plugins": ["https://plugins.dprint.dev/markdown-0.16.0.wasm"]
}

View File

@@ -9,10 +9,10 @@ test runs. Most of these files are tracked (already checked in to the
repository). There are also many new files generated as part of the most recent
test run.
I want to staging the changes to files that are already tracked, but hold off
on doing anything with the new files.
I want to stage the changes to files that are already tracked, but hold off on
doing anything with the new files.
Running `git add spec/cassettes` won't do the track because that will pull in
Running `git add spec/cassettes` won't do the trick because that will pull in
everything. Running `git add --patch spec/cassettes` will take long and be
tedious. Instead what I want is the `-u` flag. It's short for _update_ which
means it will only stage already tracked files.

View File

@@ -0,0 +1,43 @@
# Better Diffs With Delta
A `git diff` from the command line is relatively bare bones. It shows you
removed lines and added lines that make up a changeset with the former text in
red and the later text in green. All other contextual text is in white. I've
found this to be good enough for most of the life of my git usage. I've been
missing out though.
By using [`delta`](https://github.com/dandavison/delta) as the pager and diff
filter for `git`, I get a bunch of nice visual improvements.
- Removals and additions are red and green shaded backgrounds
- Syntax highlighting for most languages
- Highlight specific part of a line that has changed
- Visual spacing and layout is clearer
To get all of this, all I had to do was install `delta`:
```bash
$ brew install delta
```
And then add `delta` as both the _core_ pager and `diffFilter` in my global git
config file:
```
[core]
pager = delta
[interactive]
singleKey = true # unrelated, but nice to have
diffFilter = delta --color-only
```
It's also recommended that you use `zdiff3` for your merge conflict style,
which I already had:
```
[merge]
conflictstyle = zdiff3
```
Once you have ths all configred, try a `git diff` or `git add --patch` and see
how much more visual info you get.

View File

@@ -0,0 +1,38 @@
# Check If A File Has Changed In A Script
If I'm at the command line and I want to check if a file has changed, I can run
`git diff` and see what has changed. If I want to be more specific, I can run
`git diff README.md` to see if there are changes to that specific file.
If I'm trying to do this check in a script though, I want the command to clearly
tell the script _Yes_ or _No_. Usually a script looks for an exit code to
determine what path to take. But as long as `git diff` runs successfully,
regardless of whether or not their are changes, it is going to have an
affirmative exit code of `0`.
This is why `git diff` offers the `--exit-code` flag.
> Make the program exit with codes similar to diff(1). That is, it exits with 1
> if there were differences and 0 means no differences.
With that in mind, we can wire up a script with `git diff` that takes different
paths depending on whether or not there are changes.
```bash
if ! git diff --exit-code README.md; then
echo "README.md has changes"
else
echo "README.md is clean"
fi
```
We can take this a step further and instead use the `--quiet` flag.
> Disable all output of the program. Implies --exit-code. Disables execution of
> external diff helpers whose exit code is not trusted
This exhibits the same behavior as `--exit-code` and goes the additional step of
silencing diff output and disabling execution of external diff helpers like
`delta`.
See `man git-diff` for more details.

View File

@@ -0,0 +1,36 @@
# Check If A File Is Under Version Control
The `git ls-files` command can be used with the `--error-unmatch` flag to check
if a file is under version control. It does this by checking if any of the
listed files appears on the _index_. If any does not, it is treated as an error.
In a project, I have a `README.md` that is under version control. And I have
`node_modules` that shouldn't be under version control (which is why they are
listed in my `.gitignore` file). I can check the README and a file somewhere in
`node_modules`.
```bash
git ls-files --error-unmatch README.md
README.md
git ls-files --error-unmatch node_modules/@ai-sdk/anthropic/CHANGELOG.md
error: pathspec 'node_modules/@ai-sdk/anthropic/CHANGELOG.md' did not match any file(s) known to git
Did you forget to 'git add'?
```
Notice the second command results in an error because of the untracked
`CHANGELOG.md` file in `node_modules`.
Here is another example of this at work while specifying multiple files:
```bash
git ls-files --error-unmatch README.md node_modules/@ai-sdk/anthropic/CHANGELOG.md package.json
README.md
package.json
error: pathspec 'node_modules/@ai-sdk/anthropic/CHANGELOG.md' did not match any file(s) known to git
Did you forget to 'git add'?
```
Each tracked file gets listed and then the untracked file results in an error.
See `man git-ls-files` for more details.

View File

@@ -0,0 +1,35 @@
# Cherry Pick Multiple Commits At Once
I've always thought of `git cherry-pick` as being a command that you can run
against a single commit by specifying the SHA of that commit. That's how I've
always used it.
The man page for `git-cherry-pick` plainly states:
> Given one or more existing commits, apply the change each one introduces,
> recording a new commit for each.
We can cherry pick multiple commits at once in a single command. They will be
applied one at a time in the order listed.
Here we can see an example of applying two commits to the current branch and
the accompanying output as they are auto-merged.
```bash
$ git cherry-pick 5206af5 6362f41
Auto-merging test/services/event_test.rb
[jb/my-feature-branch 961f3deb] Use the other testing syntax
Date: Fri May 2 10:50:14 2025 -0500
1 file changed, 7 insertions(+), 7 deletions(-)
Auto-merging test/services/event_test.rb
[jb/my-feature-branch b15835d0] Make other changes to the test
Date: Fri May 2 10:54:48 2025 -0500
1 file changed, 7 insertions(+), 7 deletions(-)
```
If the commits cannot be cleanly merged, then you may need to do some manual
resolution as they are applied. Or maybe you want to try including the
`-Xpatience` merge strategy.
See `man git-cherry-pick` for more details. Make sure to look at the _Examples_
section which contains much more advanced examples beyond what is shown above.

View File

@@ -0,0 +1,26 @@
# Clear Entries From Git Stash
I often stash changes as I'm moving between branches, rebasing, or pulling in
changes from the remote. Usually these are changes that I will want to restore
with a `git stash pop` in a few moments.
However, sometimes these stashed changes are abandoned to time.
When I run `git stash list` on an active project, I see that there are nine
entries in the list. When I do `git show stash@{0}` and `git show stash@{1}` to
see the changes that comprise the latest two entries, I don't see anything I
care about.
I can get rid of those individual entries with, say, `git stash drop
stash@{0}`.
But I'm pretty confident that I don't care about any of the nine entries in my
stash list, so I want to _clear_ out all of them. I can do that with:
```bash
$ git stash clear
```
Now when I run `git stash list`, I see nothing.
See `man git-stash` for more details.

View File

@@ -0,0 +1,48 @@
# Count Number Of Commits On A Branch
The `git rev-list` command will show all commits that fit the given revision
criteria. By adding in the `--count` flag, we get a count of the number of
commits that would have been displayed. Knowing this, we can get the count of
commits for the current branch like so:
```bash
$ git rev-list --count HEAD
4
```
This finds and counts commits from `HEAD` (usually the top of the current
branch) all the back in reverse chronological order to the beginning of the
branch (typically the beginning of the repository). This works exactly as
expected for a the `main` branch.
What about when we are on a feature branch though?
Let's say we've branched off `main` and made a few commits. And now we want the
count.
```bash
$ git rev-list --count HEAD
7
```
Unfortunately, that is counting up the commits on the feature branch but it
keeps counting all the way back to the beginning of the repo.
If we want a count of just the commits on the current branch, then we can
specify a range: from whatever `main` was when we branched to the `HEAD` of
this branch.
```bash
$ git rev-list --count HEAD
3
```
This is the same as saying, I want all commits on `HEAD`, but exclude (`^`) the
commits on `main`:
```bash
git rev-list --count HEAD ^main
3
```
See `man git-rev-list` for more details.

View File

@@ -0,0 +1,32 @@
# Exclude A Directory During A Command
Many of the git commands we use, such as `git add`, `git restore`, etc., target
files and paths relative to the current directory. This is typically exactly
what we want, to stage and unstage and so forth the files and directories in
front of us.
I recently ran into a situation where I needed to restore a small subset of
changes. At the same time, I had a massive number of auto-generated files
recording HTTP interactions (hundreds of files, modified on the working tree).
I wanted to run a `git restore`, but wading through all those HTTP recording
files was not feasible.
I needed to exclude those files. They all belonged to a `spec/cassettes`
directory. I could exclude them with a _pathspec_ magic signature pattern which
is used to alter and limit the paths in a git command.
A _pathspec_ magic signature is a special pattern made up of a `:` followed by
some signature declaring what the pattern means.
The `(exclude)`, `!`, and `^` magic signatures all mean the same thing —
exclude. So, we can exclude a directory from a `git restore` command like so:
```bash
$ git restore --patch -- . ':!spec/cassettes'
```
We've employed two pathspec patterns here. The first, `.`, scopes everything to
the current directory. The second, `':!spec/cassettes'` excludes everything in
the `spec/cassettes` directory.
See `man gitglossary` for more on _pathspecs_.

View File

@@ -0,0 +1,26 @@
# Files With Local Changes Cannot Be Removed
This is a nice quality-of-life feature in `git` that should help you avoid
accidentally discarding changes that won't be retrievable.
```bash
git rm .tool-versions
error: the following file has local modifications:
.tool-versions
(use --cached to keep the file, or -f to force removal)
```
My `.tool-versions` file has some local changes. I don't realize that and I go
to issue a `git rm` command on that file. Instead of quietly wiping out my
changes, `git` lets me know I'm doing something destructive (these local
changes won't be in the diff or the reflog).
I can force the removal if I know what I'm doing with the `-f` flag. Or I can
take the two step approach of calling `git restore` on that file and then `git
rm`.
The `--cached` flag is also interesting because it doesn't actually delete the
file from my file system, but it does stage the file deletion with `git`. That
means the file now shows up as one of my untracked files.
See `man git-rm` for more details.

View File

@@ -0,0 +1,39 @@
# Fix Whitespace Errors Throughout Branch Commits
Let's say we've been working on some changes to our repository on a branch.
We've made several commits. We are close to putting up a PR, but we want to
make sure everything is tidied up.
We run a check and see that there are some whitespace errors that should be
fixed.
```bash
$ git diff main --check
README.md:1: trailing whitespace.
+# git-playground
script.sh:9: trailing whitespace.
+
```
This post isn't able to show the highlighted whitespace errors, but we can see
the warnings above.
Rather than cluttering things with an additional commit that fixes these errors
or manually cleaning up each commit, we can ask `git` to fix it for us.
```bash
$ git rebase --whitespace=fix main
```
That will do a manual rebase of each commit addressing the whitespace errors.
We can run the error check again and see no output, which means we are good to
go.
```bash
$ git diff main --check
```
See the section on `--whitespace` in `man git-apply` for more details.
[source](https://git-scm.com/book/en/v2/Customizing-Git-Git-Configuration)

View File

@@ -0,0 +1,30 @@
# Highlight Extra Whitespace In Diff Output
When running a `git diff` (or `git add --patch`) I'll sometimes come across
lines that don't have any visible changes. This is usually because some
whitespace characters were either added (on accident) or removed (often by a
autoformatter).
Depending on the `core.whitespace` config, you'll probably see at least some of
the whitespace errors that git provides. By default, git only highlights
whitespace errors on added (`new`) lines. However if some extra whitespace was
originally committed and is now being removed, it won't be highlighted on the
`old` line in the diff.
We can have git always highlight whitespace errors by setting
`wsErrorHighlight` to `all` in the global git config.
```bash
$ git config --global diff.wsErrorHighlight all
```
Which updates the global gitconfig file with the following line:
```
[diff]
wsErrorHighlight = all
```
The `all` option is a shorthand for `old,new,context`.
See `man git-diff` for more details.

View File

@@ -0,0 +1,44 @@
# Highlight Small Change On Single Line
Sometimes a change gets made on a single, long line of text in a Git tracked
file. If it is a small, subtle change, then it can be hard to pick out when
looking at the diff. A standard diff will show a green line of text stacked on
a red line of text with no more granular information.
There are two ways we can improve the diff output in these situations.
The first is built-in to git. It is the `--word-diff` flag which will visually
isolate the portions of the line that have changed.
```bash
git diff --word-diff README.md
```
Which will produce something like this:
```diff
A collection of concise write-ups on small things I learn [-day to day-]{+day-to-day+} across a
```
The outgoing part is wrapped in `[-...-]` and the incoming part is wrapped in
`{+...+}`.
The second (and my preference) is to use
[`delta`](https://github.com/dandavison/delta) as an external differ and pager
for git.
```bash
git -c core.pager=delta diff README.md
```
I cannot visually demonstrate the difference in a standard code block. So I'll
describe it. We see a red and green line stacked on each other, but with muted
background colors. Then the specific characters that are different stand out
because they are highlighted with brighter red and green. I [posted a visual
here](https://bsky.app/profile/jbranchaud.bsky.social/post/3ln245orlxs2j).
`delta` can also be added as a standard part of your config like I demonstrate
in [Better Diffs With Delta](git/better-diffs-with-delta.md).
h/t to [Dillon Hafer's post on
`--word-diff`](https://til.hashrocket.com/posts/t994rwt3fg-finds-diffs-in-long-line)

View File

@@ -0,0 +1,49 @@
# List All Files Added During Span Of Time
I wanted to get an idea of all the TIL posts I wrote during 2024. Every TIL I
write is under version control in a [git repo on
github](https://github.com/jbranchaud/til). That means git has all the info I
need to figure that out.
The `git diff` command is a good way at this problem. With the
`--diff-filter=A` flag I can restrict the results to just files that were
_Added_. And with `--name-only` I can cut all the other diff details out and
get just filenames.
But filenames added to which commits? We need to specify a ref range. There is
a ton of flexibility in how you define a ref, including [a date specification
suffix](https://git-scm.com/docs/gitrevisions#Documentation/gitrevisions.txt-emltrefnamegtltdategtemegemmasteryesterdayememHEAD5minutesagoem)
that points to the value of the ref at an earlier point in time.
So, how about from the beginning of 2024 to the beginning of 2025:
```
HEAD@{2024-01-01}..HEAD@{2025-01-01}
```
Putting that all together, we this command and potentially a big list of files.
```bash
$ git diff --diff-filter=A --name-only HEAD@{2024-01-01}..HEAD@{2025-01-01}
```
I wanted to restrict the results to just markdown files, so I added a filename
pattern.
```bash
$ git diff --diff-filter=A --name-only HEAD@{2024-01-01}..HEAD@{2025-01-01} -- "*.md"
```
I could even go a step further to see only the files added to a specific
directory.
```bash
$ git diff --diff-filter=A --name-only HEAD@{2024-01-01}..HEAD@{2025-01-01} -- "postgres/*.md"
```
As a final bonus, I can spit out the github URLs for all those files with a bit of `awk`.
```bash
$ git diff --diff-filter=A --name-only HEAD@{2024-01-01}..HEAD@{2025-01-01} -- "postgres/*.md" |
awk '{print "https://github.com/jbranchaud/til/blob/master/" $0}'
```

View File

@@ -0,0 +1,28 @@
# List All Git Aliases From gitconfig
Running the `git config --list` command will show all of the configuration
settings you have for `git` relative to your current location. Though most of
these setting probably live in `~/.gitconfig`, you may also have some locally
specified ones in `.git/config`. This will grab them all including any `alias`
entries.
We can narrow things down to just `alias` entries using the `--get-regexp` flag.
```bash
$ git config --get-regexp '^alias\.'
alias.ap add --patch
alias.authors shortlog -s -n -e
alias.co checkout
alias.st status
alias.put push origin HEAD
alias.fixup commit --fixup
alias.squash commit --squash
alias.doff reset HEAD^
alias.add-untracked !git status --porcelain | awk '/\?\?/{ print $2 }' | xargs git add
alias.reset-authors commit --amend --reset-author -CHEAD
```
I use `git doff` all the time on feature branches to "pop" the latest commmit
onto the working copy. I was trying to remember exactly what the `git doff`
command is and this was an easy way to check.

View File

@@ -0,0 +1,34 @@
# Reference Commits Earlier Than Reflog Remembers
While preparing some stats for a recent blog post on [A Decade of
TILs](https://www.visualmode.dev/a-decade-of-tils), I ran into an issue
referencing chunks of time further back than 2020.
```bash
git diff --diff-filter=A --name-only HEAD@{2016-02-06}..HEAD@{2017-02-06} -- "*.md"
warning: log for 'HEAD' only goes back to Sun, 20 Dec 2020 00:26:27 -0600
warning: log for 'HEAD' only goes back to Sun, 20 Dec 2020 00:26:27 -0600
```
This is because `HEAD@...` is a reference to the `reflog`. The `reflog` is a
local-only log of objects and activity in the repository. That date looks
suspiciously like the time that I got this specific machine and cloned the
repo.
In order to access this information, I need a different approach of finding
references that bound these points in time.
How about asking `rev-list` for the first commit it can find before the given
dates in 2017 and 2016 and then using those.
```bash
git rev-list -1 --before="2017-02-07 00:00" HEAD
17db6bc4468616786a8f597a10d252c24183d82e
git rev-list -1 --before="2016-02-07 00:00" HEAD
f1d3d1f796007662ff448d6ba0e3bbf38a2b858d
git diff --diff-filter=A --name-only f1d3d1f796007662ff448d6ba0e3bbf38a2b858d..17db6bc4468616786a8f597a10d252c24183d82e -- "*.md"
# git outputs a bunch of files ...
```

View File

@@ -0,0 +1,20 @@
# Restore File From One Branch To The Current
On one feature branch I have created some files and made changes to some
existing files as part of spiking a feature. Now I'm on a different branch
taking another shot at it. I want changes from one or two of the files. In the
past I've used `git-checkout` for this task. However, I believe this is one of
the use cases they had in mind when they added `git-restore`.
What I want to do is _restore_ the state of a file as it appears on some source
branch to my current branch. Here is what that looks like:
```bash
$ git restore --source=some-feature-branch app/models/contact.rb
```
Now when I check `git status` I'll see the state of that file on the
`some-feature-branch` branch overlayed on my current working copy. If the file
doesn't exist, it will be created.
See `man git-restore` for more details.

View File

@@ -0,0 +1,56 @@
# Set Up GPG Signing Key
I wanted to have that "Verified" icon start showing up next to my commits in
GitHub. To do that, I need to generate a GPG key, configure the secret key in
GitHub, and then configure the public signing key with my git config.
```bash
# generate a gpg key
$ gpg --full-generate-key
# Pick the following options when prompted
# - Choose "RSA and RSA" (Options 1)
# - Max out key size at 4096
# - Choose expiration date (e.g. 0 for no expiration)
# - Enter "Real name" and "Email"
(I matched those to what is in my global git config)
# - Set passphrase (I had 1password generate a 4-word passphrase)
```
It may take a few seconds to create.
I can see it was created by listing my GPG keys.
```bash
$ gpg --list-secret-keys --keyid-format=long
[keyboxd]
---------
sec rsa4096/1A8656918A8D016B 2025-10-19 [SC]
...
```
I'll need the `1A8656918A8D016B` portion of that response for the next command
and it is what I set as my public signing key in my git config.
First, though, I add the full key block to my GitHub profile which I can copy
like so:
```bash
$ gpg --armor --export 1A8656918A8D016B | pbcopy
```
And then I paste that as a new GPG Key on GitHub under _Settings_ -> _SSH and
GPG Keys_.
Last, I update my global git config with the signing key and the preference to
sign commits:
```bash
git config --global user.signingkey 1A8656918A8D016B
git config --global commit.gpgsign true
```
Without `commit.gpgsign`, I would have to specify the `-S` flag every time I
want to create a signed commit.
[source](https://git-scm.com/book/ms/v2/Git-Tools-Signing-Your-Work)

View File

@@ -0,0 +1,26 @@
# Show Summary Stats For Current Branch
When I push a branch up to GitHub as a PR, there is a part of the UI that shows
you how many lines you've added and removed for this branch. It bases that off
the target branch which is typically your `main` branch.
The `git diff` command can provide those same stats right in the terminal. The
key is to specify the `--shortstat` flag which tells `git` to exclude other diff
output and only show:
- Number of files changed
- Number of insertions
- Number of deletions
Here is the summary stats for a branch I'm working on:
```bash
git diff --shortstat main
8 files changed, 773 insertions(+), 25 deletions(-)
```
We have to be on our feature branch and then we point to the branch (or whatever
ref) we want to diff against. Since I want to know how my feature branch
compares to `main`, I specify that.
See `man git-diff` for more details.

View File

@@ -0,0 +1,23 @@
# Use External Diff Tool Like Difftastic
Assuming we already have a tool like `difft`
([difftastic](https://difftastic.wilfred.me.uk/introduction.html)) available on
our machine, we can use it as a diff viewer for the various `git` commands that
display a diff.
This requires a manual override which involve two pieces — an inline
configuration of `diff.external` specifying the binary of the external differ
and the `--ext-diff` flag which tells these commands to use the external diff
binary.
Here is what `git show` looks like with `difft`:
```bash
$ git -c diff.external=difft show --ext-diff
```
Without the `--ext-diff` flag, it will fallback to the default differ despite
`diff.external` being set.
See `man git-diff` and friends for the `--ext-diff` flag. See `man git-config`
for `diff.external`.

View File

@@ -0,0 +1,41 @@
# Use Labels To Block PR Merge
Let's say our GitHub project has custom tags for both `no merge` and `wip`
(_work in progress_). Whenever either of those labels has been applied to a PR,
we want there to be a failed check so as to block the merge. This is useful to
ensure automated tools (as well as someone not looking closely enough) don't
merge a PR that isn't _ready to go_.
This can be achieved with a basic GitHub Actions workflow that requires no
3rd-party actions. We can add the following as
`.github/workflows/block-labeled-prs.yml` in our project.
```yaml
name: Block Labeled PR Merges
on:
pull_request:
types: [labeled, unlabeled, opened, edited, synchronize]
jobs:
prevent-merge:
if: ${{ contains(github.event.*.labels.*.name, 'no merge') || contains(github.event.*.labels.*.name, 'wip') }}
name: Prevent Merging
runs-on: ubuntu-latest
steps:
- name: Check for label
run: |
echo "Pull request label prevents merging."
echo "Labels: ${{ join(github.event.*.labels.*.name, ', ') }}"
echo "Remove the blocking label(s) to skip this check."
exit 1
```
This workflow is run when a pull request is opened, when it is edited or
synchronized, and when a label change is made. The job `prevent-merge` sees if
any of the label names match `no merge` or `wip`. If so, we echo out some
details in the ubuntu container and then `exit 1` to fail the check.
Shoutout to [Jesse Squire's
implementation](https://www.jessesquires.com/blog/2021/08/24/useful-label-based-github-actions-workflows/#updated-21-march-2022)
which I've heavily borrowed from here.

View File

@@ -0,0 +1,25 @@
# Access Your GitHub Profile Photo
Let's say I have my [GitHub profile](https://github.com/jbranchaud) pulled up in
the browser.
```
https://github.com/jbranchaud
```
If I then add `.png` to the end of that in the URL bar:
```
https://github.com/jbranchaud.png
```
I'll be redirected to the URL where the full image file lives. In my case:
```
https://avatars.githubusercontent.com/u/694063?v=4
```
You can pull up yours `https://github.com/<username>.png` to access your profile
image.
[source](https://dev.to/10xlearner/how-to-get-the-profile-picture-of-a-github-account-1d82)

View File

@@ -0,0 +1,19 @@
# Open A PR To An Unforked Repo
Sometimes I will clone a repo to explore the source code or to look into a
potential bug. If my curiosity takes me far enough to make some changes, then I
jump through the hoops of creating a fork, reconfiguring branches, pushing to my
fork, and then opening the branch as a PR against the original repo.
The `gh` CLI allows me to avoid all that hoop-jumping. Directly from the cloned
repo I can use `gh` to create a new PR. It will prompt me to creat a fork. If I
accept, it will seamlessly create it and then open a PR from my fork to the
original.
```bash
$ gh pr create
```
This allows me to create the PR with a few prompts from the CLI. If you prefer,
you can include the `--web` flag to open the PR creation screen directly in the
browser.

View File

@@ -0,0 +1,20 @@
# Target Another Repo When Creating A PR
I have a [`dotfiles` repo](https://github.com/jbranchaud/dotfiles) that I forked
from [`dkarter/dotfiles`](https://github.com/dkarter/dotfiles). I'm adding a
bunch of my own customizations on a `main` branch while continually pulling in
and merging upstream changes.
The primary remote according to `gh` is `jbranchaud/dotfiles`. 98% of the time
that is what I want. However, I occasionally want to share some changes upstream
via a PR. Running `gh pr create` as is will create a PR against my fork. To
override this on a one-off basis, I can use the `--repo` flag.
```bash
$ gh pr create --repo dkarter/dotfiles
```
This will create a PR against `dkarter:master` from my branch (e.g.
[`jbranchaud:jb/fix-hardcoded-paths`](https://github.com/dkarter/dotfiles/pull/373)).
See `man gh-pr-create` for more details.

View File

@@ -0,0 +1,38 @@
# Tell gh What The Default Repo Is
I recently forked [dkarter/dotfiles](https://github.com/dkarter/dotfiles) as a
way of bootstrapping a robust dotfile config for a new machine that I could
start making customizations to. I'm maintaining a `my-dotfiles` branch and keep
things in sync with the original upstream repo.
When trying to go to *my* fork of the repo
([jbranchaud/dotfiles](https://github.com/jbranchaud/dotfiles)) in the web with
the `gh` CLI tool, I ran into a weird issue. It was instead opening up to
`dkarter/dotfiles`.
`gh` was under the wrong impression which repo should be considered the default.
To clarify things for `gh`, there is a command to set the default repo.
```bash
$ gh repo set-default jbranchaud/dotfiles
✓ Set jbranchaud/dotfiles as the default repository for the current directory
```
Now when I run `gh repo view --web`, it opens the browser to my fork of the
dotfiles.
But where does this setting live?
Opening this repo's `.git/config` file I can see a section for the `origin`
remote that includes a new line for `gh-resolved`. This being set to `base`
tells `gh` that this remote is the one to treat as the default repo.
```
[remote "origin"]
url = git@github.com:jbranchaud/dotfiles.git
fetch = +refs/heads/*:refs/remotes/origin/*
gh-resolved = base
```
See `gh repo set-default --help` for more details.

View File

@@ -0,0 +1,63 @@
# Basic Delve Debugging Session
When using [delve](https://github.com/go-delve/delve) to debug a Go program,
these are the series of things I usually find myself doing.
First, I start running the program with `dlv` including any arguments after a `--` (in my case, the `solve` subcommand and a filename).
```bash
$ dlv debug . -- solve samples/001.txt
```
`dlv` starts up and is ready to run my program from the beginning. I'll need to
set a couple breakpoints before continuing. I do this with the `break` command,
specifying the filename and line number.
```
(dlv) break main.go:528
Breakpoint 1 set at 0x10c1a5bea for main.traversePuzzleIterative() ./main.go:528
(dlv) break main.go:599
Breakpoint 2 set at 0x10c1a6dcc for main.traversePuzzleIterative() ./main.go:599
```
Now I can continue which will run the program until hitting a breakpoint.
```
(dlv) continue
> [Breakpoint 2] main.traversePuzzleIterative() ./main.go:599 (hits goroutine(1):1 total:1) (PC: 0x10c1a6dcc)
594: }
595: }
596:
597: topStackFrame := stack[len(stack)-1]
598: // if the current stack frame has more values, try the next
=> 599: if len(topStackFrame.PossibleValues) > 0 {
600: nextValue := topStackFrame.PossibleValues[0]
601: topStackFrame.PossibleValues = topStackFrame.PossibleValues[1:]
602: topStackFrame.CurrValue = nextValue
603:
604: // Undo the last placement and make a new one
```
I can see the context around the line we've stopped on. From here I can dig
into the current state of the program by looking at local variables (`locals`)
or printing out a specific value (`print someVar`). I can continue to step
through the program line by line with `next` or eventually run `continue` to
proceed to the next breakpoint.
```
(dlv) locals
diagnostics = main.Diagnostics {BacktrackCount: 0, NodeVisitCount: 1, ValidityCheckCount: 2,...+2 more}
stack = []main.StackData len: 1, cap: 1, [...]
emptyCellPositions = [][]int len: 3, cap: 4, [...]
emptyCellIndex = 1
status = "Invalid"
topStackFrame = main.StackData {RowIndex: 1, ColumnIndex: 7, PossibleValues: []int len: 8, cap: 8, [...],...+1 more}
(dlv) print topStackFrame
main.StackData {
RowIndex: 1,
ColumnIndex: 7,
PossibleValues: []int len: 8, cap: 8, [2,3,4,5,6,7,8,9],
CurrValue: 1,}
(dlv) next
> main.traversePuzzleIterative() ./main.go:600 (PC: 0x10c1a6dea)
```

View File

@@ -0,0 +1,41 @@
# Check If Cobra Flag Was Set
When using [Cobra](https://github.com/spf13/cobra) to define a CLI, we can
specify a flag for a command like so:
```go
var Seed int64
myCmd.PersistentFlags().Int64VarP(&Seed, "seed", "", -1, "set a seed")
```
This `--seed` flag has a _default_ of `-1`. If the flag isn't specified, then
when we access that flag's value, we'll get `-1`.
But how do we differentiate between the _default_ `-1` and someone passing `-1`
to the `--seed` flag when running the program?
In the command definition, we can look at the flags and see, by name, if
specific ones were changed by user input rather than being the defaults.
```go
myCommand := &cobra.Command{
// coommand setup ...
Run: func(cmd *cobra.Command, args []string) {
if cmd.Flags().Changed("seed") {
seed, err := cmd.Flags().GetInt64("seed")
if err != nil {
fmt.Println("Seed flag is missing from `cmdFlags()`")
os.Exit(1)
}
fmt.Printf("Seed was set to %d\n", seed)
} else {
fmt.Println("Seed was not set")
}
}
}
```
If we don't want to rely on the default and instead want to specify some other
behavior when the flag is not manually set by the user, we can detect that
scenario like this.

View File

@@ -0,0 +1,29 @@
# Configure Max String Print Length For Delve
During a [Delve](https://github.com/go-delve/delve) debugging session, we can
print out the value of a given variable with the `print` command. Similarly, we
can see the values of all local variables with the `locals` command.
Whenever Delve is printing out strings and slices, it will truncate what it
displays to 64 characters (or items) by default.
```go
(dlv) print diagnostics.Solutions[0]
"295743861\n431865972\n876192543\n387459216\n612387495\n549216738\n7635...+25 more"
```
This can be overridden by [changing the `config` of
`max-string-len`](https://github.com/derekparker/delve/blob/237c5026f40e38d2dd6f62a7362de7b25b00c1c7/Documentation/cli/expr.md?plain=1#L59)
to something longer. In my case here, all I need are about 90 characters to
display my full string, so run `config max-string-len 90` from the `dlv`
session.
```go
(dlv) config max-string-len 90
(dlv) print diagnostics.Solutions[0]
"295743861\n431865972\n876192543\n387459216\n612387495\n549216738\n763524189\n928671354\n154938627"
```
Now I can see the entire string instead of the truncated version.
[source](https://stackoverflow.com/a/52416264/535590)

View File

@@ -0,0 +1,50 @@
# Connect To A SQLite Database
Using the `database/sql` module and the `github.com/mattn/go-sqlite3` package,
we can connect to a SQLite database and run some queries. In my case, I have a
SQLite connection string exported to my environment, so I can access that with
`os.Getenv`. It's a local SQLite file, `./test.db`.
Calling `sql.Open`, I'm able to connect with a SQLite3 driver to the database
at that connection string. The `setupDatabase` function returns that database
connection pointer. Things like `Exec` and `QueryRow` can be called on `db`. I
also need to make sure I close the connection to the database with a `defer`.
Here is a full example of connecting to a local SQLite database and inserting a
record:
```go
package main
import (
"database/sql"
"fmt"
"os"
_ "github.com/mattn/go-sqlite3"
)
func setupDatabase() *sql.DB {
databaseString := os.Getenv("GOOSE_DBSTRING")
if len(databaseString) == 0 {
fmt.Println("Error retrieving `GOOSE_DBSTRING` from env")
os.Exit(1)
}
db, err := sql.Open("sqlite3", databaseString)
if err != nil {
fmt.Printf("Error opening database: %v\n", err)
os.Exit(1)
}
return db
}
func main() {
db := setupDatabase()
defer db.Close()
sql := `insert into users (name) values (?);`
db.Exec(sql, "Josh")
}
```

View File

@@ -0,0 +1,44 @@
# Create A Slice From An Array
Slices in Go are a flexible abstraction over arrays. We can create a slice from
an array with the `[n:m]` _slicing_ syntax. We specify the left and right
(exclusive) bounds of the array that we want to create the slice relative to.
We can exclude the lower bound which translates to the `0` index of the array.
We can exclude the left bound which translates to the end of the array. We can
even exclude both ends of the _slicing_ syntax which means creating a slice of
the entire array.
Here is an example of each of those:
```go
package main
import "fmt"
func main() {
arr := [...]string{
"taco",
"burrito",
"torta",
"enchilada",
"quesadilla",
"pozole",
}
firstTwo := arr[:2]
lastTwo := arr[len(arr)-2:]
all := arr[:]
fmt.Println("First two:", firstTwo)
// First two: [taco burrito]
fmt.Println("Last two:", lastTwo)
// Last two: [quesadilla pozole]
fmt.Println("All:", all)
// All: [taco burrito torta enchilada quesadilla pozole
}
```
[source](https://go.dev/blog/slices-intro#slices)

View File

@@ -0,0 +1,59 @@
# Detect If Stdin Comes From A Redirect
Reading lines of input from `stdin` is flexible. And we may need our program to
behave differently depending on where that input is coming from. For instance,
if data is redirected or piped to our program, we scan and process it directly.
Otherwise, we need to prompt the user to enter in specific info and go from
there.
We can detect whether [`os.Stdin`](https://pkg.go.dev/os#pkg-variables) is
being piped to, redirected to, or whether we should prompt the user by looking
at the file mode descriptor of
[`os.Stdin.Stat()`](https://pkg.go.dev/os#File.Stat).
```go
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
file, err := os.Stdin.Stat()
if err != nil {
fmt.Printf("Error checking stdin: %v\n", err)
os.Exit(1)
}
fromTerminal := (file.Mode() & os.ModeCharDevice) != 0
fromAPipe := (file.Mode() & os.ModeNamedPipe) != 0
if fromTerminal {
fmt.Println("This is Char Device mode, let's prompt user for input")
termScanner := bufio.NewScanner(os.Stdin)
for termScanner.Scan() {
fmt.Printf("- %s\n", termScanner.Text())
break;
}
} else if fromAPipe {
fmt.Println("This is Named Pipe mode, contents piped in")
pipeScanner := bufio.NewScanner(os.Stdin)
for pipeScanner.Scan() {
fmt.Printf("- %s\n", pipeScanner.Text())
}
} else {
fmt.Println("This means the input was redirected")
redirectScanner := bufio.NewScanner(os.Stdin)
for redirectScanner.Scan() {
fmt.Printf("- %s\n", redirectScanner.Text())
}
}
}
```
If `os.ModeCharDevice` then we are connected to a character device, like the
terminal. We can see if input is being piped in by checking against
`os.ModeNamedPipe`. Otherwise, there are a variety of file modes and I'm
willing to assume we're dealing with a regular file redirect at that point.

View File

@@ -0,0 +1,49 @@
# Deterministically Seed A Random Number Generator
If you need a random number in Go, you can always reach for the various
functions in the `rand` package.
```go
package main
import (
"fmt"
"math/rand"
)
func main() {
for range 5 {
roll := rand.Intn(6) + 1
fmt.Printf("- %d\n", roll)
}
}
```
Each time I run that, I get a random set of values. Often in programming, we
want some control over the randomness. We want to _seed_ the randomness so that
it is deterministic. We want random, but the kind of random where we know how
we got there.
```go
package main
import (
"fmt"
"math/rand"
)
func main() {
seed := int64(123)
src := rand.NewSource(seed)
rng := rand.New(src)
for range 5 {
roll := rng.Intn(6) + 1
fmt.Printf("- %d\n", roll)
}
}
```
In this second snippet, we create a `Source` with a specific seed value that we
can use with a custom `Rand` struct. We can then deterministically get random
numbers from it.

View File

@@ -0,0 +1,55 @@
# Difference Between Slice And Pointer To Slice
Though a slice can be thought of and used as a flexible, variable-length
array-like data structure, it is important to understand that it is also a
special kind of pointer to an underlying array.
This matters when we a function receives a slice versus a pointer to a slice as
an argument, depending on what it is doing with that slice.
If the function is access or updating elements in the slice, there is no
difference. There is no meaningful difference between these two functions and
we might as well use the former.
```go
func replaceAtIndex(slice []string, index int, value string) {
slice[index] = value
}
func replaceAtIndexPtr(slice *[]string, index int, value string) {
(*slice)[index] = value
}
```
On the other hand, if the receiving function needs to append to or replace the
slice, then we need to pass a pointer to the slice. A direct slice argument
will result in only the function-local copy getting replaced.
```go
package main
import (
"fmt"
)
func main() {
s1 := []int{8, 6, 7, 9}
s2 := []int{8, 6, 7, 9}
addItem(s1, 11)
fmt.Printf("s1: %v\n", s1) //=> s1: [8 6 7 9]
addItemPtr(&s2, 11)
fmt.Printf("s2: %v\n", s2) //=> s2: [8 6 7 9 11]
}
func addItem(slice []int, value int) {
slice = append(slice, value)
}
func addItemPtr(slice *[]int, value int) {
(*slice) = append(*slice, value)
}
```
[source](https://go.dev/tour/moretypes/8)

View File

@@ -0,0 +1,51 @@
# Format Date And Time With Time Constants
The Go [`time` package](https://pkg.go.dev/time) has a [`Format`
function](https://pkg.go.dev/time#Time.Format) for displaying the parts of a
date and time in standard and custom ways. It works a bit different than you
might be used to from other languages. Rather than using `strftime` identifiers
like in this string `"%B %d, %Y"`, there is a canonical date that is used as a
reference point.
That canonical date is from Janary 2nd, 2006. That was a Monday. It was at 5
seconds after 3:04PM. The Unix format of it looks like `"Mon Jan _2 15:04:05
MST 2006"`.
```
package main
import (
"fmt"
"time"
)
func main() {
// This specific time pulled from `time.Format` docs
t, _ := time.Parse(time.UnixDate, "Wed Feb 25 11:06:39 PST 2015")
// Reference date and time:
// "Mon Jan _2 15:04:05 MST 2006"
strf1 := t.Format("|2006|02|01|03:04:05|Day: Mon|")
fmt.Println("strf1:", strf1)
// strf1: |2015|25|02|11:06:39|Day: Wed|
strf2 := t.Format(time.DateTime)
strf3 := t.Format(time.RubyDate)
strf4 := t.Format(time.Kitchen)
fmt.Println("DateTime:", strf2) // DateTime: 2015-02-25 11:06:39
fmt.Println("RubyDate:", strf3) // RubyDate: Wed Feb 25 11:06:39 +0000 2015
fmt.Println("Kitchen:", strf4) // Kitchen: 11:06AM
}
```
Though there are a [variety of useful formatting
constants](https://pkg.go.dev/time#pkg-constants) already available like
`DateTime`, `RubyDate`, `Kitchen`, etc., we can also define our own formatting
string by using the reference values for each part of a date and time.
If you want to reference the year, whether as `YYYY` or `YY`, it is always
going to be a form of `2006`, so `2006` or `06` respectively. Even though the
above time variable is in February, our format strings will always need to use
one of `Jan`, `January`, `01` or `1`.

View File

@@ -0,0 +1,65 @@
# Pass A Struct To A Function
Go operates as _pass-by-value_ which means that when we pass a struct to a
function, the receiving function gets a copy of the struct. Two things worth
noticing about that are 1) an extra memory allocation happens when calling the
function and 2) altering the struct does not affect the original in the calling
context.
On the other hand, we can have a function that takes a pointer to a struct.
When we call that function, we have a reference to the memory location of the
struct instead of a copy of the struct. That means no additional allocation and
modifications to the dereferenced struct are modifications to the original in
the calling context.
Here is an example that demonstrates both of these. Notice the printed output
that is included in comments at the end which shows memory locations and
contents of the struct at various points.
```go
package main
import "fmt"
type Order struct {
Item string
Quantity int
DineIn bool
}
func main() {
order := Order{Item: "taco", Quantity: 3, DineIn: true}
fmt.Println("Order:", order)
fmt.Printf("main - Loc: %p\n", &order)
doubledOrder := doubleOrder(order)
fmt.Println("Double Order:", doubledOrder)
fmt.Println("Original Order:", order)
doubleOrderPtr(&order)
fmt.Println("Double Order Ptr:", order)
}
func doubleOrder(order Order) Order {
fmt.Printf("doubleOrder - Loc: %p\n", &order)
order.Quantity *= 2
return order
}
func doubleOrderPtr(order *Order) {
fmt.Printf("doubleOrderPtr - Loc: %p\n", order)
(*order).Quantity *= 2
}
// Order: {taco 3 true}
// main - Loc: 0xc0000b4000
// doubleOrder - Loc: 0xc0000b4040
// Double Order: {taco 6 true}
// Original Order: {taco 3 true}
// doubleOrderPtr - Loc: 0xc0000b4000
// Double Order Ptr: {taco 6 true}
```

View File

@@ -0,0 +1,32 @@
# Produce The Zero Value For A Generic Type
While writing a _pop_ function that would work with slices of a generic type, I
ran into the issue of needing to produce a zero value of type `T` when
returning early for an empty slice.
The way to arbitrarily get the zero value of a generic in Go is with `*new(T)`.
I was able to use this in my `Pop` function like so:
```go
func Pop[T any](slice []T) (T, error) {
if len(slice) == 0 {
return *new(T), fmt.Errorf("cannot pop an empty slice")
}
lastItem := slice[len(slice)-1]
slice = slice[:len(slice)-1]
return lastItem, nil
}
```
If this is happening in multiple functions and we want a more self-documenting
approach, we can pull it out into a function `zero`:
```go
func zero[T any]() T {
return *new(T)
}
```

View File

@@ -0,0 +1,39 @@
# Redirect File To Stdin During Delve Debug
I have a go program that accepts input from stdin. The way I've been running
the program as I develop it is to redirect the output of some sample files to
the program.
```bash
$ go run . < sample/001.txt
```
When I then go to debug this program with
[Delve](https://github.com/go-delve/delve), I'd still like to be able to
redirect a file into the program to reproduce the exact behavior I'm seeing.
The following won't work:
```bash
$ dlv debug . < samples/001.txt
Stdin is not a terminal, use '-r' to specify redirects for the target process or --allow-non-terminal-interactive=true if you really want to specify a redirect for Delve
```
Fortunately, `dlv` sees what I'm trying to do and makes a recommendation. The
`-r` flag can be used to specify redirects for the target process. The [`dlv`
redirect
docs](https://github.com/go-delve/delve/blob/master/Documentation/usage/dlv_redirect.md)
explain that `-r` can be passed a `source:destination`. The `source` is `stdin`
by default, but can also be `stdout` and `stderr`.
I can redirect my file into the debugging session of my program like so:
```bash
$ dlv debug . -r stdin:samples/001.txt
```
Or even more succinctly:
```bash
$ dlv debug . -r samples/001.txt
```

View File

@@ -0,0 +1,58 @@
# Write A Custom Scan Function For File IO
By default a [`bufio.Scanner`](https://pkg.go.dev/bufio#Scanner) will scan
input line-by-line. In other words, splitting on newlines such that each
iteration will emit everything up to the next newline character.
We can write our own `SplitFunc` and override the default one by calling
`scanner.Split` with it. Our custom scan function needs to match the type
signature of [`SplitFunc`](https://pkg.go.dev/bufio#SplitFunc).
Here is a custom one that emits each individual character but omits the
newlines.
```go
func ScanChar(data []byte, atEOF bool) (int, []byte, error) {
if atEOF || len(data) == 0 {
return 0, nil, nil
}
start := 0
for start < len(data) {
if !utf8.FullRune(data[start:]) {
return 0, nil, nil
}
r, size := utf8.DecodeRune(data[start:])
if r == utf8.RuneError {
return 0, nil, fmt.Errorf("invalid UTF-8 encoding")
}
if r != '\n' {
return start + size, data[start:start+size], nil
}
// found a \n, advance the start position
start += size
}
return start, nil, nil
}
```
We can then use thi `ScanChar` function with a `bufio.Scanner` like so:
```go
func ReadFileByCharacter(file io.Reader) {
scanner := bufio.NewScanner(file)
// override default SplitFunc
scanner.Split(scanChar)
for scanner.Scan() {
char := scanner.Text()
fmt.Printf("- %s\n", char)
}
}
```

View File

@@ -0,0 +1,34 @@
# Specify Default Team And App For Project
Typically when you run commands with the Heroku CLI you'll need to specify the
name of the app on Heroku you're targeting with the `--app` flag. However, to
first see the names of the apps you may want to run `heroku apps` (or `heroku
list`). That will list the apps for your default team.
If you need to see apps for a different team (i.e. organization), you'll need to
specify that team either with the `--team` flag or by setting that as an
environment variable.
Here I do the latter in an `.envrc` file:
```
# Heroku
export HEROKU_ORGANIZATION=visualmode
```
Once that is set and the environment reloaded, running `heroku apps` will show
the apps specific to that team on Heroku.
Similarly, if you want to set a default app for your project so that you don't
have to always specify the `--app` flag, you can update your `.envrc`
accordingly.
```
# Heroku
export HEROKU_ORGANIZATION=visualmode
export HEROKU_APP=my-app
```
I had a hard time finding official documentation for this which is why I'm
writing this up here. I've manually verified this works with my own team and
app.

View File

@@ -0,0 +1,39 @@
# Allow Number Input To Accept Decimal Values
Here is a number input element:
```html
<input type="number" id="amount" required class="border" />
```
This renders an empty number input box with up and down arrows which will, by
default, increment or decrement the value by **1**.
Of course, I can manually edit the input typing in a value like `1.25`.
However, when I submit that via an HTML form, the submission will be prevented
and the browser will display a validation error.
> Please enter a valid value. The two nearest valid values are 1 and 2.
If I want to be able to input a decimal value like this, I need to change the
`step` value. It defaults to `1`, but I could change it to `2`, `10`, or in
this case to `0.01`.
```html
<input type="number" step="0.01" id="amount" required class="border" />
```
Notice now that as you click the up and down arrows, the value is incremented
and decremented by **0.01** at a time.
If I want to maintain the step value of `1` while allowing decimal values, I
can instead set the `step` value to be `any`.
```html
<input type="number" step="any" id="amount" required class="border" />
```
See the [MDN docs on number
inputs](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/input/number)
for more details.

View File

@@ -0,0 +1,28 @@
# Disclose Additional Details
You can add extra details to an HTML page that are only disclosed if the user
chooses to disclose them. To do that, we use the `<details>` tag. This tag
needs to have a `<summary>` tag nested within it. Anything else nested within
`<details>` will be what is disclosed when it is toggled open. The `<summary>`
is what is displayed when it is not open.
Here is a `<detail>` block I recently added to [Ruby Operator
Lookup](https://www.visualmode.dev/ruby-operators).
```html
<details className="pt-2 pb-6">
<summary>What is this thing?</summary>
<p className="pl-3 pt-2 text-gray-700 text-sm">
Ruby is an expressive, versatile, and flexible dynamic programming language. That means there are all kinds of syntax features, operators, and symbols we can encounter that might look unfamiliar and are hard to look up. Ruby Operator Lookup is a directory of all these language features.
</p>
<p className="pl-3 pt-2 text-gray-700 text-sm">
Use the search bar to narrow down the results. Then click on a button for the operator or symbol you want to explore further.
</p>
</details>
```
On page load, the only thing we see is "What is this thing?" with a triangle
symbol next to it. If we click the summary, then the entire details block
(those two `<p>` tags) are disclosed.
[source](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/details)

View File

@@ -0,0 +1,34 @@
# Download A Google Doc As Specific Format
I was recently given a public Google Doc URL and I was curious if I could
download it from the command line. I didn't want to have to install special CLI
though. I was hoping to use something like `curl`.
A brief chat with Claude and I learned that not only can I use `curl`, but I
can specify the format in the _export_ URL.
```bash
$ export GOOGLE_DOC_URL="https://docs.google.com/document/d/157rMgHeBf76T9TZnUjtrUyyS2XPwG0tObr-OjYNfMaI"
$ echo $GOOGLE_DOC_URL
https://docs.google.com/document/d/157rMgHeBf76T9TZnUjtrUyyS2XPwG0tObr-OjYNfMaI
$ curl -L "$GOOGLE_DOC_URL/export?format=pdf" -o doc.pdf
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 414 0 414 0 0 2763 0 --:--:-- --:--:-- --:--:-- 2895
100 16588 0 16588 0 0 56214 0 --:--:-- --:--:-- --:--:-- 167k
$ ls doc.pdf
doc.pdf
```
I append `/export` and then include the `?format=pdf` query param to specify
that I want the document to be exported in PDF format. With the `-o` flag I can
specify the name and extension of the output file.
This is a handy on its own, but noticing that Google Docs supports other export
formats, I thought it would be useful to go back-and-forth with Claude to
sketch out a script that can do this and prompt me (with `fzf`) for the file
type -- [here is the gist for
`gdoc-download`](https://gist.github.com/jbranchaud/cf3d2028107a1bd8484eed7cca0fcdab).

View File

@@ -0,0 +1,27 @@
# Grab The RSS Feed For A Substack Blog
I've been attempting to put more energy into finding and reading blog posts via
an RSS feed reader. This as opposed to scrolling and scrolling and hoping that
the algorithm turns up an interesting article or two.
A lot of people who have been blogging for a while have a handy RSS feed link
prominently displayed on their site. We love to see it!
There are a few people whose writing I really enjoy that distribute their words
via Substack. I couldn't find a prominent or not prominent RSS feed link
anywhere on someone's Substack. What I did learn, after some searching, is that
you can tack `/feed` onto the end of someone's Substack URL and that will give
you the XML feed.
For example:
```
Substack blog landing page URL:
https://registerspill.thorstenball.com
Substack blog RSS feed URL:
https://registerspill.thorstenball.com/feed
```
Grab that feed URL and paste it into your feed reader and you should start
seeing their stuff show up.

View File

@@ -0,0 +1,42 @@
# Format A List Of Items By Locale
The `Intl` module includes a [`ListFormat`
object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/ListFormat)
which can be used to format a list of items in a consistent way across locales.
I've reinvented the wheel of writing a helper function numerous times across
projects for formatting a list of items that accounts for formatting based on
how many items there are. This built-in function handles that with the added
benefit of working across locales.
Here are lists of three, two, and one items formatted in the `long` styles for
US english.
```javascript
> const formatter = new Intl.ListFormat('en', { style: 'long', type: 'conjunction' });
undefined
> formatter.format(['Alice', 'Bob', 'Carla'])
'Alice, Bob, and Carla'
> formatter.format(['Coffee', 'Tea'])
'Coffee and Tea'
> formatter.format(['Taco'])
'Taco'
```
The difference between `long` and `short` style for a `conjunction` is _and_
versus _&_. In addition to the type`conjunction`, you could also use
`disjunction` which will do an _or_ instead of an _and_. I'm not sure what
you'd use the `unit` type for.
You could use another locale, such as French, as well:
```javascript
> const formatter = new Intl.ListFormat('fr', { style: 'long', type: 'conjunction' });
undefined
> formatter.format(['café', 'thé'])
'café et thé'
```

View File

@@ -0,0 +1,28 @@
# Describe Current Changes And Create New Change
One of the first patterns I learned with `jj` was a pair of commands to
essentially "commit" the working copy and start a fresh, new change. So if I am
done making some changes, I can add a description to the `(no description)`
working copy and then start a new working copy _change_.
```bash
$ jj describe -m "Add status subcommand to show current status"
$ jj new
```
I learned from [Steve](https://steveklabnik.com/) in the [jj
discord](https://discord.gg/dkmfj3aGQN) that a shorthand for this pattern is to
use the `jj commit` command directly.
> When called without path arguments or `--interactive`, `jj commit` is
> equivalent to `jj describe` followed by `jj new`.
That means, instead of the above pair of commands, I could have done:
```bash
$ jj commit -m "Add status subcommand to show current status"
```
That would have had the same result in my case. However, notice the caveats
mentioned in the quote above and check out `man jj-commit` for more details on
that.

View File

@@ -0,0 +1,31 @@
# Squash Changes Into Parent Commit Interactively
While I have some changes in progress as part of the working copy, I can squash
them into the previous / parent commit with the `jj squash` command. Running
that command as is will apply all the working copy changes to the parent leaving
the current revision empty.
I can also interactively squash those changes similar in spirit to how I might
use `git add --patch` to stage and then amend specific changes into the previous
commit with `git`. This can be done with [`jj`](https://github.com/jj-vcs/jj)
using `squash` with the `-i` flag.
```bash
jj squash -i # or --interactive
```
This will open up a TUI where I can click around or use keys. Each file in the
source revision (in my case, the working copy) will be listed. I can move the
cursor between them hitting _space_ to toggle them in or out of the squash
selection.
I can also hit `f` over a given file to toggle _folding_. When folding is on, a
diff of the file will be disclosed with checkboxes for toggling individual
hunks and lines.
Once I'm satisfied with my interactive selection, I can hit `c` to confirm and
only the selected files and changes will be squashed into the parent.
See `man jj-squash` for more details.
[source](https://steveklabnik.github.io/jujutsu-tutorial/real-world-workflows/the-squash-workflow.html)

View File

@@ -0,0 +1,51 @@
# Add A Bunch Of CLI Utilities With coreutils
The [`coreutils`](https://www.gnu.org/software/coreutils/) project is a
collection of useful utilities that every operating system ought to have.
> The GNU Core Utilities are the basic file, shell and text manipulation
> utilities of the GNU operating system. These are the core utilities which are
> expected to exist on every operating system.
While many of these utilities are redundant with BSD utilities that MacOS
chooses to ship with, there are some differences in the overlapping ons and then
many additions from `coreutils`.
They can be installed with Homebrew:
```bash
$ brew install coreutils
```
And then you should have some new things available on your path. Take `shuf`, for
instance. This utility can shuffle and select items from a file or incoming
lines from another command. Here I use it to randomly grab a number between 1
and 5 (with the help of `seq`):
```bash
seq 1 5 | shuf -n 1
3
seq 1 5 | shuf -n 1
2
seq 1 5 | shuf -n 1
5
```
Or how about some utilities for manipulating file names? Among others there is
`realpath`, `basename`, and `dirname`.
```bash
realpath README.md
/Users/lastword/dev/jbranchaud/til/README.md
realpath README.md | xargs basename
README.md
realpath README.md | xargs dirname
/Users/lastword/dev/jbranchaud/til
```
See the [manual](https://www.gnu.org/software/coreutils/manual/coreutils.html)
for many more details.

View File

@@ -0,0 +1,27 @@
# Capture Screenshoot To Clipboard From CLI
MacOS comes with a `screencapture` utility that you can run from the terminal
to activate the built-in screenshot functionality on Mac.
Usually when I am taking a screenshot, I want to do something with it right
away. Such as paste it into an application or group chat. The `-c` flag forces
the screen capture to go the clipboard.
I also generally want to capture a specific area of the screen so that the
captured image includes the right amount of context and nothing more. The `-i`
flag puts you in interactive screen capture mode. That means your cursor will
turn into a crosshair that you can use to make a drag selection of the capture
area.
```bash
$ screencapture -ic
```
Select an area to capture, it's now on your clipboard, paste it where you need
it.
Note: The first time you run this command, your terminal program (e.g. iTerm2)
may prompt you for the necessary OS permissions in order to capture images of
your screen. You'll need to grant those permissions and then rerun the command.
See `man screencapture` for more details.

View File

@@ -0,0 +1,39 @@
# Detect How Long A User Has Been Idle
The `ioreg` utility on MacOS dumps the I/O Kit registry tree. This lets us look
at the state of all hardware devices and drivers registered with I/O Kit.
Looking specifically at the Human Interface Device subsystem (`IOHIDSystem`), we
can find a handful of properties including the `HIDIdleTime`.
```bash
$ ioreg -c IOHIDSystem | awk '/HIDIdleTime/'
| | | "HIDIdleTime" = 91831000
```
That value is the number of nanoseconds since a human input device was last
interacted with. That is the amount of time the user (me) has been idle.
I can convert this to seconds, which is the small amount of time between me
hitting enter in the terminal and the command finding the idle time.
```bash
$ ioreg -c IOHIDSystem | awk '/HIDIdleTime/ {printf "%.2f seconds\n", $NF/1000000000}'
0.13 seconds
```
I can run this in `watch` to see the elapsed idle time increment.
```bash
watch -n 1 "echo -n 'Idle time: '; ioreg -c IOHIDSystem | awk '/HIDIdleTime/ {printf \"%.1f seconds\\n\", \$NF/1000000000}'"
```
After watching the _idle time_ increment for a bit, I can move the mouse and
watch it reset on the next `watch` loop.
This could be used as part of a script that takes certain actions after the user
has been idle for a while, like putting the display to sleep or stopping a time
tracker app.
There is a _lot_ going on in the `ioreg` output and it's hard to make sense of
hardly any of it. I found running `ioreg -c IOHIDSystem | less`, searching for
`IdleTime`, and browsing from there to be a good starting point.

View File

@@ -0,0 +1,41 @@
# Inspect Assertions Preventing Sleep
The `pmset` command is for inspecting and manipulating _Power Management
Settings_ on MacOS. The `-g` flag is for _getting_ details. We can get a summary
of power assertions with `-g assertions`. These assertions are ways that the
system and display are prevented from sleeping.
A common assertion preventing sleep is the user being active. Another example of
an assertion is a program like `caffeinate` that sets a timeout preventing sleep
for a fixed period of time.
Here I activate a 30 minute (1600 second) `caffeinate` session and then I
inspect the power management assertions which shows the details of that
assertion as well as two others.
```bash
caffeinate -t 1600 &
[1] 98217
pmset -g assertions
2025-11-02 13:20:57 -0600
Assertion status system-wide:
BackgroundTask 0
ApplePushServiceTask 0
UserIsActive 1
PreventUserIdleDisplaySleep 0
PreventSystemSleep 0
ExternalMedia 0
PreventUserIdleSystemSleep 1
NetworkClientActive 0
Listed by owning process:
pid 98217(caffeinate): [0x00045477000194b3] 00:00:03 PreventUserIdleSystemSleep named: "caffeinate command-line tool"
Details: caffeinate asserting for 1600 secs
Localized=THE CAFFEINATE TOOL IS PREVENTING SLEEP.
Timeout will fire in 1597 secs Action=TimeoutActionRelease
pid 145(WindowServer): [0x00044f2f00099212] 00:00:00 UserIsActive named: "com.apple.iohideventsystem.queue.tickle serviceID:10009be9e service:AppleUserHIDEventService product:CTRL Keyboard eventType:3"
Timeout will fire in 600 secs Action=TimeoutActionRelease
pid 80(powerd): [0x00044f2f00019216] 00:22:34 PreventUserIdleSystemSleep named: "Powerd - Prevent sleep while display is on"
```
See `man pmset` and `man caffeinate` for more details.

View File

@@ -0,0 +1,36 @@
# Launch Some Confetti
If you have [Raycast](https://www.raycast.com/) installed on your machine, then
you have quick access to some confetti via their quick command palette. Trigger
the command palette to open, start typing `confetti` until it appears as the
focused option, and then hit enter.
🎉
We can launch confetti other ways, including programmatically from scripts.
To do this, we need to first find the _deeplink_ for the Raycast _confetti_
program. Trigger the command palette and type out `confetti` again. However,
this time instead of hitting enter, hit `Cmd+k` to open other actions. Find the
_Copy Deeplink_ option.
You should now have this on your clipboard:
```
raycast://extensions/raycast/raycast/confetti
```
With this deeplink in hand, we can now trigger confetti other places. The
easiest way to do this is to open a terminal and pass that deep link as an
argument to `open`.
```bash
$ open raycast://extensions/raycast/raycast/confetti
```
Now you can wrap that up in any old bash script or even just tack it on to the
end of a run of your test suite:
```bash
$ rails test && open raycast://extensions/raycast/raycast/confetti
```

View File

@@ -0,0 +1,30 @@
# Prevent Sleep With The Caffeinate Command
MacOS has a built-in utility `caffeinate` that can programatically prevent your
machine from sleeping. There are two kinds of sleep that it can prevent via
_assertions_.
> caffeinate creates assertions to alter system sleep behavior.
The two kinds of sleep behavior are _display sleep_ and _system idle sleep_. An
assertion to prevent display sleep can be created with `-d` and system idle
sleep with `-i`.
We can combine those to prevent both and then specify a duration (_timeout_)
with `-t` (with a value in seconds).
```bash
caffeinate -d -i -t 600
```
This creates assertions with 10 minute timeouts for both display and system idle
sleep.
The `caffeinate` command is blocking, so if you want to start it in the
background, you can do that like so:
```bash
caffeinate -d -i -t 600 &
```
See `man caffeinate` for more details.

View File

@@ -0,0 +1,37 @@
# Start Amphetamine Session With AppleScript
I use the _Amphetamine_ app on Mac to keep my computer from going to sleep
during the day. It is a menu bar app that can be used to start a _Session_ of
time where it will keep your computer from going to sleep. At the start of my
day, I'll typically start an 8 hour _Session_. This is useful if I have to step
away fo 10 minutes or if I'm doing some writing in my notebook, my computer
won't go to sleep on me.
Though these sessions can be controlled from the menu bar app, I was excited to
learn that I can also programatically start a session with AppleScript.
Here is how to start a _Session_ (overriding an existing session) with options
that specify it is 8 hours long and the display should not be allowed to sleep.
```bash
$ osascript -e 'tell application "Amphetamine" to start new session with options {duration:8, interval:hours, displaySleepAllowed:false}'
```
The `interval` could also be `minutes` and then I could change the duration to
an amount of time that makes sense in minutes, e.g. `90` for 1.5 hours.
Note: the `with options {...}` segement is all or nothing. All three need to be included or don't include the clause at all.
Additionally, a session of indefinite duration can be started by including no options:
```bash
$ osascript -e 'tell application "Amphetamine" to start new session'
```
And any existing session can be ended with:
```bash
$ osascript -e 'tell application "Amphetamine" to end session'
```
[source](https://iffy.freshdesk.com/support/solutions/articles/48000078223-applescript-documentation)

View File

@@ -0,0 +1,17 @@
# Uninstall LogiTech G Hub From Mac
I rarely uninstall software from my Mac. And unless the software is nice enough
to provide a clear 'Uninstall' flow, it is not straightforward how to do it. In
fact, it probably varies quite a bit from app to app.
In the case of LogiTech's G Hub, I was able to find the following instructions
for uninstalling it. The thing of note is that the updater app can take an
`--uninstall` flag.
```bash
sudo /Applications/lghub.app/Contents/MacOS/lghub_updater.app/Contents/MacOS/lghub_updater --uninstall
```
I still had to remove the app launcher from my `Applications` directory.
[source](https://www.reddit.com/r/LogitechG/comments/bluth5/comment/lbhctx1/)

View File

@@ -0,0 +1,25 @@
# Use A Different Font With iTerm2
I wanted to give [`gh-dash`](https://github.com/dlvhdr/gh-dash) a try, but
after installing and opening it up, I was seeing a bunch of `?` characters
where specialized font icons were missing. Their README recommended installing
a [`Nerd Font`](https://github.com/ryanoasis/nerd-fonts) that includes those
icons, such as [`Fira Code`](https://github.com/tonsky/FiraCode).
I was able to install `font-fira-code-nerd-font` with homebrew:
```bash
$ brew install font-fira-code-nerd-font
```
Then to get iTerm2 to start using that font, I had to change the font setting
for my current profile.
Under the _iTerm2_ menu is _Settings..._. From there, I clicked the _Profiles_
section. For the _Default_ profile, I went to the _Text_ tab and under _Font_ I
selected _FireCode Nerd Font Mono_ from the dropdown.
That won't take effect on any current iTerm2 windows. Since I have everything
running through `tmux`, I could close my current window, open a new one
(`Cmd+N`), and reconnect to my existing `tmux` session. Now when I run `gh
dash`, I see all the font icons that were missing before.

View File

@@ -0,0 +1,53 @@
# Create Umbrella Task For All Test Tasks
When I was first sketching out the [`mise`
tasks](https://mise.jdx.dev/tasks/running-tasks.html) for a Rails app, I added
the following two tasks. One is for running all the `rspec` tests. The Other is
for running all the `vitest` (JavaScript) tests.
```toml
[tasks."test:rspec"]
run = "unbuffer bundle exec rspec"
description = "Run RSpec tests"
depends = ["bundle-install"]
[tasks."test:vitest"]
run = "unbuffer yarn test run"
description = "Run Vitest tests"
depends = ["node-install"]
```
I didn't want to have to invoked both of this individually every time I wanted
to run the full suite. So I added a `test:all` task to do it all.
```toml
[tasks."test:all"]
description = "Run all tests (RSpec and Vitest)"
run = [
"unbuffer bundle exec rspec",
"unbuffer yarn test run",
]
description = "Run RSpec tests"
depends = ["bundle-install", "node-install"]
```
This worked (for now). But it ate at me, for a couple reasons. I had to
duplicate everything about the existing `test:rspec` and `test:vitest` tasks.
And this didn't account for a new kind of test task being added (e.g.
`test:e2e`).
Instead, I can rely on `depends` and wildcards to achieve this without the
duplication which makes it more future-proof.
```toml
[tasks."test:all"]
description = "Run all tests (RSpec and Vitest)"
depends = ["test:*"]
```
Running `mise run test:all` won't execute its own command, but because it
depends on all other `test:*` tasks, the tests will get run through those
dependencies.
This task naming pattern also allows for calling all tests with `mise run
"test:**"`.

View File

@@ -0,0 +1,29 @@
# List The Files Being Loaded By Mise
While running `mise` for the first time, after adding a `mise.toml` file to a
project, I noticed something strange. Instead of invoking the command I had
specified (`mise run dev`), several parellel tool downloads were kicked off. In
addition to Ruby, it was installing an older version of Postgres, and lua. What
gives?
By running `mise cfg`, I can list all the files being loaded by `mise` and get
to the bottom of this.
```bash
mise cfg
Path Tools
~/.tool-versions node, ruby, postgres, lua
~/code/still/.ruby-version ruby
~/code/still/Gemfile (none)
~/code/still/.tool-versions ruby
~/code/still/mise.toml (none)
```
I was only thinking about the files local to my project and I forgot that I
have a system-wide `.tool-versions` file. As we can see from the output, that
file specifies `postgres` and `lua` as well. Mise wanted to ensure that it had
downloaded the specified versions of each of those tools before running my
task.
[source](https://mise.jdx.dev/configuration.html)

View File

@@ -0,0 +1,45 @@
# Preserve Color Output For Task Command
I decided to wrap a couple test running commands for a project into a single
`test:all` mise task. It looked something like this:
```toml
[tasks."test:all"]
run = """
bundle exec rspec
yarn test run
"""
description = "Run all tests (RSpec and Vitest)"
depends = ["bundle-install", "node-install"]
```
I can run this with `mise run test:all` and it works. However, there is a
glaring issue that immediately juts out. All of the test runner output is
uncolored text. I'm used to and strongly prefer greens (passes), reds (fails),
and yellows (skips) of test runner output.
The test runners lose the text coloring when run through `mise` because they
believe they are not running in _interactive_ mode.
The [`expect`](https://linux.die.net/man/1/expect) tools (`brew install
expect`) install with another binary called
[`unbuffer`](https://linux.die.net/man/1/unbuffer). `unbuffer` can coerce a
command to run in interactive mode. Prepending these test runner commands with
`unbuffer` will preserve the colors as the results are output to the terminal.
Here is the update `test:all` task:
```toml
[tasks."test:all"]
run = """
unbuffer bundle exec rspec
unbuffer yarn test run
"""
description = "Run all tests (RSpec and Vitest)"
depends = ["bundle-install", "node-install"]
```
For some commands, it seems able to stream out (rather than _buffer_) the
results (e.g. with `vitest`). Whereas with `rspec`, the test suite runs to
completion and is then output to the terminal. I'm still investigating
streaming the `rspec` results.

View File

@@ -0,0 +1,28 @@
# Read Existing Dot Env File Into Env Vars
Just about any web app that I've worked on has had a `.env` file as a way of
configuring aspects of the app specific to that environment. These typically
are read into the environment with a language-specific
[dotenv](https://github.com/bkeepers/dotenv) tool.
Mise supports this convention. In addition to specifying individual non-secret
env vars, you can also instruct `mise` to read-in a `.env` file like so:
```toml
[env]
PORT=3344
_.file = ".env"
```
The `_.file` line tells `mise` that there is a file `.env` with key-value pairs
that it should read in. It can even handle `.env.json` and `.env.toml` file
formats.
To ensure that `mise` is picking up the values from the `.env` file, you can
run the following command and make sure they show up in the output:
```bash
$ mise env
```
[source](https://mise.jdx.dev/environments/secrets.html)

View File

@@ -0,0 +1,39 @@
# Run A Command With Specific Tool Version
Because I'm using `mise` to manage the versions of tools like Node, I can
execute commands in the context of specific versions. Behind the scenes `mise`
makes sure I have the necessary tool(s) installed at the desired version(s).
So, [`mise exec` command](https://mise.jdx.dev/cli/exec.html) will default to
using the latest version of a tool if I haven't been more specific. At the time
of this writing, for Node, that is v23.
```bash
$ mise exec node -- node --version
v23.9.0
```
To be specific I could specify the major version with `node@23` like so:
```bash
mise exec node@23 -- npx repomix
Need to install the following packages:
repomix@0.2.39
Ok to proceed? (y) y
...
```
Or if I wanted to use a different, older version of Node, I could specify that
as well. We can see it will first install that and then execute the command:
```bash
$ mise exec node@22 -- npx repomix
gpg: Signature made Tue Feb 11 04:44:53 2025 CST
gpg: using RSA key C0D6248439F1D5604AAFFB4021D900FFDB233756
gpg: Good signature from "Antoine du Hamel <duhamelantoine1995@gmail.com>" [unknown]
📦 Repomix v0.2.39
...
```

View File

@@ -0,0 +1,40 @@
# Get Idea Of What Is In A JSON Column
While digging through some data trying to reacquaint myself with the overall
schema and data model, I ran into an issue selecting rows from this
`content_resource` table. There was so much text packed in to the `"body"`,
`"summary"`, and `"description"` key-value pairs of `fields` JSON column that a
simple `select * ... limit 3;` was overwhelming the screen with text and table
formatting characters (i.e. `+------+-------`).
I figured the `fields` JSON followed a reliable structure, at least for records
of the same `type`. So, let's start by only grabbing the
[`json_keys`](https://dev.mysql.com/doc/refman/8.4/en/json-search-functions.html#function_json-keys)
so that I can get a sense of the shape of the JSON.
```sql
select id, json_keys(fields)
from content_resource
where type = 'post'
limit 3;
+-----+-----------------------------------------------------------------------------------------------------------+
| id | json_keys(`fields`) |
+-----+-----------------------------------------------------------------------------------------------------------+
| 1 | ["body", "slug", "state", "title", "summary", "postType", "visibility", "description", "originalLessonId"] |
| 2 | ["body", "slug", "state", "title", "summary", "postType", "visibility", "description", "originalLessonId"] |
| 3 | ["body", "slug", "state", "title", "summary", "postType", "visibility", "description", "originalLessonId"] |
+-----+-----------------------------------------------------------------------------------------------------------+
```
For the `post` type, I see the same keys for this sampling of rows. Now I have
an idea what keys are present and can start digging in further.
My next query might look something like this:
```sql
select id, fields->'$.slug', fields->'$.title', fields->'$.state'
from content_resource
where type = 'post'
limit 3;
```

View File

@@ -0,0 +1,46 @@
# Jump Between Changes In Current File
With the [gitsigns.nvim plugin](https://github.com/lewis6991/gitsigns.nvim) for
Neovim, I get some handy Git-related capabilities like gutter highlighting of
additions, deletions, and changes to lines in the current file. These contiguous
sections of modification to the versioned state of a file are called hunks.
Here are two mappings (in Lua) for gitsigns that allow me to jump to the next
(`]h`) or previous (`[h`) hunk in the current file.
```lua
---@type LazyKeysSpec[]
M.gitsigns_mappings = {
-- Navigation
{
']h',
function()
if vim.wo.diff then
vim.cmd.normal { ']c', bang = true }
else
require('gitsigns').nav_hunk 'next'
end
end,
desc = 'Next Hunk',
},
{
'[h',
function()
if vim.wo.diff then
vim.cmd.normal { '[c', bang = true }
else
require('gitsigns').nav_hunk 'prev'
end
end,
desc = 'Prev Hunk',
},
}
```
This is particularly useful when I've just opened a big file and I want to jump
directly to active changes in that file.
I got this mapping directly from [Dorian's
dotfiles](https://github.com/dkarter/dotfiles).

View File

@@ -0,0 +1,23 @@
# Run nvim With Factory Defaults
Most of the fun of using Neovim is tailoring it to your exact needs with custom
configurations. Your configuration can be made up of environment variables,
`init.lua`/`init.vim`, and user directories on the `runtimepath`.
Perhaps though, you want to load neovim with its "factory defaults". You want
to ignore all your custom config and your _shada_ (shared data) file. I wanted
to do just that recently to verify that neovim has the `ft-manpage` plugin
enabled by default (as opposed to enabled somewhere in the labryinth of my
config files).
The `--clean` flag does just this. It loads built-in plugins, but none of the
user defined config.
```bash
$ nvim --clean
```
This is different than `nvim -u NONE` which excludes all plugins, including
built-in ones.
See `man nvim` and `:help --clean` for more details.

1
notes Submodule

Submodule notes added at 897184eb02

View File

@@ -0,0 +1,23 @@
# See What Databases You Have Access To
Assuming you have the `pscale` CLI installed and you've authenticated with it,
you can run the following to view available databases.
```bash
$ pscale database list
NAME KIND CREATED AT UPDATED AT
----------- ------- ------------- -------------
bookshelf mysql 3 years ago 3 years ago
```
I'm not very active on my personal account. Planetscale is a multi-tenant SaaS
though. I can switch from my personal `org` to another team I have access to.
```bash
$ pscale org switch another-team
```
And then from there I can run `pscale database list` again to see what databases
I have access to from this other organization.
See `pscale database help` and `pscale org help` for more details.

View File

@@ -0,0 +1,39 @@
# Check The Size Of Databases In A Cluster
The `\l` command in `psql` will list all the databases for the server. The
field surfaced by this meta-command are:
- Name
- Owner
- Encoding
- Locale Provider
- Collate
- Ctype
- ICU Locale
- ICU Rules
- Access privileges
If we add a `+`, issuing instead `\l+`, we get three additional fields:
- Size
- Tablespace
- Description
The _Size_ column is the human-formatted size of each database.
Another way to do this is with some SQL querying the underlying record keeping
of the server's database.
```sql
select
db.datname as db_name,
pg_size_pretty(pg_database_size(db.datname)) as db_size
from pg_database db
order by pg_database_size(db.datname) desc;
```
Credit to [this StackOverflow
answer](https://stackoverflow.com/a/18907188/535590) for how to do this with a
SQL query.
[source](https://www.postgresql.org/docs/current/app-psql.html#APP-PSQL-META-COMMAND-LIST)

View File

@@ -0,0 +1,56 @@
# Count The Number Of Items In An Array
There are two ways to count the number of items in an array with PostgreSQL.
The one that might jump out at you or show up at the top of search results is
[`array_length`](https://www.postgresql.org/docs/current/functions-array.html).
```sql
> select array_length(array[1,2,3], 1);
+--------------+
| array_length |
|--------------|
| 3 |
+--------------+
> select array_length(array[[1,2], [3,4]], 2);
+--------------+
| array_length |
|--------------|
| 2 |
+--------------+
```
This requires specifying the dimension at which you want to check the length.
The first example, checking the 1st dimension of a one-dimensional array, seems
like the more common and useful scenario. In the second example, we are
checking the 2nd dimension.
The other way we can determine the number of items in an array is with the
[`cardinality`](https://www.postgresql.org/docs/current/functions-array.html)
function.
> Returns the total number of elements in the array, or 0 if the array is
> empty.
```sql
> select cardinality(array[1,2,3]);
+-------------+
| cardinality |
|-------------|
| 3 |
+-------------+
> select cardinality(array[[1,2], [3,4]]);
+-------------+
| cardinality |
|-------------|
| 4 |
+-------------+
```
This behaves the same as `array_length` for a one-dimensional array and doesn't
require a second argument. Where it gets more interesting is with
multi-dimensional arrays. It returns the total number of elements in the
arrayregardless of the nesting.
[source](https://mattrighetti.com/2025/01/20/you-dont-need-sql-builders)

View File

@@ -0,0 +1,58 @@
# Create And Execute SQL Statements With \gexec
The [`\gexec`
meta-command](https://www.postgresql.org/docs/current/app-psql.html#APP-PSQL-META-COMMAND-GEXEC)
is a variation of the [`\g`
meta-command](https://www.postgresql.org/docs/current/app-psql.html#APP-PSQL-META-COMMAND-G),
both of which can be used in a `psql` session. Whereas the `\g` command sends
the current query in the buffer to the PostgreSQL server for execution, the
`\gexec` command first sends the query to the server for execution and then
executes each row of the result as its own SQL statement.
This is both a bit absurd and powerful. And a bit unnecessary considering all
of the scripting capabilities with anything from bash to any language with a
SQL client library.
Nevertheless, let's take a look at a contrived example of how it works. Here,
we have a SQL statement that does some string concatenation based off values in
an array. This results in three separate `create schema` statements.
```sql
> select
'create schema if not exists schema_' || letter || ';'
from unnest(array['a', 'b', 'c']) as letter
\gexec
CREATE SCHEMA
CREATE SCHEMA
CREATE SCHEMA
> \dn
List of schemas
Name | Owner
----------+-------------------
public | pg_database_owner
schema_a | postgres
schema_b | postgres
schema_c | postgres
(4 rows)
```
Three new schemas get created which we can inspect with `\dn`.
Notice, if we simply execute the primary statement, we can see the intermediate
result that `\gexec` will subsequently execute.
```sql
> select
'create schema if not exists schema_' || letter || ';'
from unnest(array['a', 'b', 'c']) as letter
\g
?column?
---------------------------------------
create schema if not exists schema_a;
create schema if not exists schema_b;
create schema if not exists schema_c;
(3 rows)
```

View File

@@ -0,0 +1,49 @@
# Fetch Data From An Endpoint In SQL
The [`pgsql-http` extension](https://github.com/pramsey/pgsql-http) provides a
variety of functions for allowing PostgreSQL to act as an HTTP client. This is
a bit unorthodox and may not be a good idea in production systems. That said,
it is cool that it is possible. Let's look at an example of it.
First, I've installed the extension on the Docker container running my local
Postgres server.
```bash
$ docker exec -it still-postgres-1 bash
$ apt-get update
$ apt-get install postgres-16-http # I'm running Postgres v16
$ exit
```
Then I'll connect to a `psql` session in that container for the `postgres` database.
```bash
$ docker exec still-postgres-1 psql -U postgres -d postgres
```
Then I enable the extension.
```sql
> create extension if not exists http;
CREATE EXTENSION
```
Now I can point a PostgreSQL statement at a live endpoint like
[https://httpbun.com/ip](https://httpbun.com/ip) which will respond with a
chunk of JSON including the IP address for that project's server. I do this
using `http_get` which makes a `GET` request to the given endpoint. The body is
included in the result set.
```bash
> select content from http_get('http://httpbun.com/ip');
content
-----------------------------
{ +
"origin": "73.75.236.101"+
} +
(1 row)
```

View File

@@ -0,0 +1,37 @@
# References Target Primary Key By Default
Typically when I am creating a table or adding a column that involves a foreign
key constraint, I explicitly name the reference column.
```sql
create table contacts (
id int generated always as identity primary key,
user_id int references users(id);
);
```
The [Create Table PostgreSQL
Docs](https://www.postgresql.org/docs/17/sql-createtable.html) point out that
specifying the reference column isn't strictly necessary.
> These clauses specify a foreign key constraint, which requires that a group
> of one or more columns of the new table must only contain values that match
> values in the referenced column(s) of some row of the referenced table. If
> the refcolumn list is omitted, the primary key of the reftable is used.
If we're using the primary key as the reference column, then we can choose to
omit the reference column.
```sql
create table contacts (
id int generated always as identity primary key,
user_id int references users;
);
```
In the same way we can do this when adding a column.
```sql
alter table contacts
add column account_id int references account;
```

View File

@@ -0,0 +1,35 @@
# Set Up A Project-Local Cluster With Postgres.app
I want to set up a PostgreSQL cluster in my project directory. This helps
provide some separation and clarity that this cluster and its databases are just
for this project.
This can be done with `Postgres.app` (on Mac) hitting the `+` button in the
bottom left corner of the app. This will pop open a "Create new server" modal.
From there, you'll want to give the server a name that you can identify within
`Postgres.app`. E.g. "<App Name> Cluster"
Then select the Postgres version. My existing project is still on 17, so I'll
select that.
The not so intuitive part is the _Data Directory_. Use the "Choose..." file
picker to find the root directory of your project. Select that. Then click into
the text input for the data directory and append the name of the data directory
_to be created_ to that path. If I want it to all go in `postgres-data`, then my
path will look like:
```
/Users/me/dev/my-app/postgres-data
```
The `postgres-data` directory doesn't exist yet. But it will in a moment.
You probably want the default port, so leave that at `5432` unless you know
otherwise.
Click `Create server`, though that won't actually create the server yet. Now
with that server selected in `Postgres.app` click the `Initialize` button. That
will create the `postgres-data` directory and then run `initdb` under the hood
which will add everything your server needs. It will now be running at that
port, ready to connect.

View File

@@ -0,0 +1,35 @@
# Show Reconstructed Constraints For A Table
The [`pg_get_constraintdef`
function](https://pgpedia.info/p/pg_get_constraintdef.html) can be used to
reconstruct the command for creating a given constraint. This isn't necessarily
the command (or commands) that originally created the constraint, but rather a
reconstruction.
We have to pass it an `oid` that corresponds to the constraint which we can get
from the `pg_constraint` table. These results can be further narrowed down by
the `conname` (constraint name) and `conrelid` (table name).
Here is an example of listing the constraints on a `reading_statuses` table.
```sql
> select
conname,
pg_get_constraintdef(oid)
from pg_constraint
where conrelid = 'reading_statuses'::regclass;
conname | pg_get_constraintdef
-------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
reading_statuses_pkey | PRIMARY KEY (id)
fk_rails_17ee7cb2c4 | FOREIGN KEY (user_id) REFERENCES users(id)
fk_rails_0d3729339f | FOREIGN KEY (book_id) REFERENCES books(id)
reading_statuses_valid_status_check | CHECK (((status)::text = ANY ((ARRAY['started'::character varying, 'completed'::character varying, 'abandoned'::character varying, 'already_read'::character varying])::text[])))
(4 rows)
```
I came across this while experimenting with [an idea for a fail-fast Rails
initializer
check](https://gist.github.com/jbranchaud/12813a0558f9cd06bcc24b7d8706550c)
that verifies the values of the `reading_statuses_valid_status_check` stay in
sync with the Rails version of those values that live in a constant.

View File

@@ -0,0 +1,58 @@
# Trim Leading And Trailing Space From String
PostgreSQL has a bunch of [string
functions](https://www.postgresql.org/docs/current/functions-string.html),
including several for doing various string trimming.
We can use the simplest form of `trim` to remove leading and trailing space
characters from a string.
```sql
> select trim(' Taco Cat ');
+----------+
| btrim |
|----------|
| Taco Cat |
+----------+
```
The syntax for calling `trim` is a bit odd relative to other PostgreSQL
functions and functions in other languages. Here is the "grammar" as described
in the docs:
```
trim ( [ LEADING | TRAILING | BOTH ] [ characters text ] FROM string text ) → text
```
We pick `leading`, `trailing`, or `both`, with `both` being the default. Then
we specify the character(s) we want to remove. This is also optional, the
default being the space character. Then we say `from` what string we want to
trim those characters.
Here we remove all sequential spaces from `both` ends of the given string:
```sql
> select trim(both from ' Taco Cat ');
+----------+
| btrim |
|----------|
| Taco Cat |
+----------+
```
To further demonstrate how `trim` works, here we remove all sequences made up
of any of spaces, uppercase `T`, and lowercase `t` from `both` ends of the
string:
```sql
> select trim(both ' Tt' from ' Taco Cat ');
+--------+
| btrim |
|--------|
| aco Ca |
+--------+
```
Notice that in all the above examples the column name of the result is `btrim`.
That's probably because `btrim` (_trim both ends_) is being called under the
hood for the `both` option.

View File

@@ -0,0 +1,45 @@
# Unable To Infer Data Type In Production
Inspired by [You Probably Don't Need Query
Builders](https://mattrighetti.com/2025/01/20/you-dont-need-sql-builders), I
wrote a query in one of my applications that has filter clauses that get
short-circuited if the filter value hasn't been included.
That query looked something like this:
```ruby
@tags =
Tag.where("? is null or normalized_value ilike ?", normalized_query, "%#{normalized_query}%")
.order(:normalized_value)
.limit(10)
```
The `normalized_value ilike ?` filtering won't be applied if the
`normalized_query` value isn't present (`nil`). This helps me avoid writing
messy ternaries or if-else conditional query building madness.
Unfortunately, when I shipped this query to production, the page started
failing and Postgres was reporting this error in the logs.
```
Caused by: PG::IndeterminateDatatype (ERROR: could not determine data type of parameter $1)
```
The query is prepared as a parameterized statement and Postgres appears to be
unable to determine the datatype of the first parameter (`$1`) —
`normalized_query`.
I was unable to reproduce the issue in development. It was only occuring in
production. Until I can come up with a root cause analysis, I have the
following fix that does a casting to `text`. This helps out with the type
inference and makes the issue go away.
```ruby
@tags =
Tag.where("cast(? as text) is null or normalized_value ilike ?", normalized_query, "%#{normalized_query}%")
.order(:normalized_value)
.limit(10)
```
Interestingly, this person using `pgtyped` [ran into the exact same issue with
the same type of query](https://github.com/adelsz/pgtyped/issues/354).

Some files were not shown because too many files have changed in this diff Show More