summaryrefslogtreecommitdiffhomepage
path: root/src/blog/extend/index.gsp
blob: ce2b5fd42651ee70a2710c9bd7e6211ab040aa05 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
html lang="en" {
	head { m4_include(head.gsp) }
	body {
		header {
			div {
				h1 {-Dmenu is a Godsend}
				m4_include(nav.gsp)
			}

			figure .quote {
				blockquote {
					p {=
						Because dwm is customized through editing its source code, it’s
						pointless to make binary packages of it.  This keeps its userbase
						small and elitist.  No novices asking stupid questions.
					}
				}
				figcaption {-https://dwm.suckless.org}
			}
		}

		main {
			h2 #simple {-Simple Software}
			p {-
				In a @a href="/blog/gsp" {-previous article} I talked a bit about
				software simplicity, or perhaps maybe the lack of it that exists in the
				world.  One of my favorite parts of UNIX-like systems is the
				composability of command-line tools.  Instead of having giant monolithic
				programs that do everything, you have various small domain-specific
				tools that all use a common interface — standard-input and -output.  The
				following is a good example of this:
			}

			figure {
				pre {= m4_fmt_code(compose.sh.gsp) }
			}

			p {-
				I have a m4_abbr(YAML) file on my system with various fun quotes, and I
				like to have a quote-of-the-day that’s displayed when I open a terminal.
				I can make use of the @code{-yq} program which is specialized in
				querying m4_abbr(YAML) files to extract the list of quotes from the
				file.  I can then use the @code{-shuf} program to shuffle the quotes and
				pick one at random, and finally I can use the @code{-tr} program to
				translate null-bytes to newlines.
			}

			p {-
				Notice how all three of these tools are very specialized to a specific
				domain; they don’t try to reinvent the wheel, instead offloading the
				tasks they aren’t specialized to do to other tools.  @code{-yq} doesn’t
				waste its time with functionality to shuffle lists of items because you
				can do it with @code{-shuf} instead.  This mindset of composability
				allows you the user to create tools that are more powerful than they
				could have been otherwise.  Instead of hoping that all your tools offer
				support for shuffling items @em{-and} hoping that they can shuffle
				things in the specific way you like, you can just use the one single
				shuffling tool @code{-shuf} everywhere.
			}

			p {-
				In my example I used @code{-shuf} to pick a random quote, but I could
				similarly use it to pick a random song from a playlist, or to pick a
				random image to use as a desktop wallpaper.
			}

			p {-
				So with the composability of the UNIX environment being such a great
				thing, it blows my mind that people are still writing software such as
				@code{-kitty} that try to do absolutely everything in one giant
				monolithic program instead of keeping focused to the task at hand and
				allowing the user to extend their tools to add in the functionality they
				so desire.
			}

			figure {
				figcaption {-Kitty’s unicode input screen}
				img
					alt="Kitty’s Unicode Input"
					src="unicode.jpg"
					style="width: 100%;"
				{}
			}

			p {-
				Some of you have surely already figured out what my issue is with what
				Kitty has done here, and why I think this is shitty software design.
				For those that haven’t, allow me to ask you a question:
				@em{-what would be better than unicode input in your terminal?}
			}

			p {-
				The answer is simple: @em{-unicode input everywhere.}
			}

			p {-
				Why should you be limited to unicode input in your terminal?  What if
				you’re texting your friend or sending an email, and want to include a
				unicode symbol such as ‘™’, or want to properly refer to a site you
				visited such as Ta’ Ħaġrat?  Perhaps you even have a friend whose
				surname is Mäkelä.  Or maybe — you just want to send your friends a
				middle-finger emoji sometimes.
			}

			p {-
				Wouldn’t it be nice if you had a @em{-global} menu for unicode input?
				Well turns out it’s actually really damn easy to do yourself, and
				renders all that Kitty code absolutely useless.
			}

			h2 #scripting {-Writing the Script}
			p {-
				The first thing you’re probably going to need if you want to have your
				own unicode-input tool is a list of all the unicode characters out
				there.  Luckily for you, I already went through the hell that is the
				@a href="https://unicode.org" {-Unicode website} to find it for you.
			}

			figure {
				pre {= m4_fmt_code(download.sh.gsp) }
			}

			p {-
				You can check out the file for yourself if you want.  It’s got a bunch
				of information in it — a lot of which is really useless for our
				purposes.  There are also a bunch of control characters and other things
				in there that I personally don’t care for, so those can probably be
				removed too.  If it tickles your fancy, I’ve written a @code{-sed}
				script to clean up the input into something a bit nicer:
			}

			figure {
				pre {= m4_fmt_code(cleanup.sed.gsp) }
			}

			p {-
				After processing, your unicode data file should look something like
				this:
			}

			figure {
				pre {= m4_fmt_code(unicode.txt.gsp) }
			}

			aside {
				p {-
					You know how I inserted that sample of my unicode data file you see
					right above this?  By using a small- and simple command-line tool in
					the form of @code{-head} to grab the first 10 lines of the file, and
					then using another small- and simple command-line tool in the form of
					@code{-wl-copy} to copy those 10 lines to my clipboard.  Take that
					Kitty.
				}
			}

			p {-
				Now that you have your data file, we can begin scripting.  The first
				thing we want is to get all of the names of the unicode characters.
				Turns out that is a very easy task thanks to the @code{-cut} utility.
				We can split each line on a semicolon and extract the second field with
				a simple command, and then we can compose it together with @code{-dmenu}
				or your preferred clone of it to present the user with a graphical list
				of items they can pick from:
			}

			figure {
				pre {= m4_fmt_code(dmenu.sh.gsp) }
			}

			p {-
				Notice how we can simply compose @code{-cut} and @code{-dmenu} together,
				and just assign the result to a variable.  We can do this because these
				are sane programs that read from standard-input, perform some simple,
				basic task, and then print a result to standard-output.  One tool to
				parse a file, and another tool to let the user pick a selection.
			}

			p {-
				We have the users selection now, the @code{-$name} variable holds the
				name of the unicode character that the user selected.  All that we need
				now is to actually get the unicode @em{-character} of our choosing.
				Luckily this is @em{-also} incredibly easy thanks to composition:
			}

			figure {
				pre {= m4_fmt_code(program.sh.gsp) }
			}

			p {-
				Congratulations!  That entire script, which can be easily condensed down
				into only 2 lines of code is all you need to create a graphical
				interface that allows you to pick a unicode character, and then copies
				your selection to your clipboard — and it was all done by taking simple
				tools and combining them to make a creater application.
			}

			p {-
				So next time you’re developing software and want to add a new feature,
				just pause and think for a second.  Do you @em{-need} that feature?  Can
				it be done in a better way?  It is possible to generalize your feature
				to where it is useful outside of just your specific application?  Don’t
				make the same mistake Kitty did.  Allow me to leave you with this quote:
			}

			figure .quote {
				blockquote {
					p {=
						The talk reviews reasons for UNIX’s popularity and shows, using UCB
						@code{-cat} as a primary example, how UNIX has grown fat.
						@code{-cat} isn’t for printing files with line numbers, it isn’t for
						compressing multiple blank lines, it’s not for looking at
						non-printing ASCII characters, it’s for concatenating files.
					}
					p {=
						We are reminded that @code{-ls} isn’t the place for code to break a
						single column into multiple ones, and that @code{-mailnews}
						shouldn’t have its own @code{-more} processing or joke encryption
						code.
					}
				}
				figcaption {-USENIX Summer Conference Proceedings, 1983}
			}

			h2 #good-bad {-The Good, The Bad, and The Ugly}
			p {-
				I would like to take a moment to point out some examples of
				composability done right, and some examples of features that are
				actively harmful in the pursuit of the UNIX ideal.
			}

			h3 {-Ls — Bad}
			aside {
				p {-
					This is already referenced in the above quote, but I added that quote
					after this section was already written.
				}
			}

			p {-
				The @code{-ls} program is one of the most useful ones found in the UNIX
				environment.  It has a simple job to perform and it does it well.  It
				lists files in a directory.  So what’s the issue then?  Well let’s see
				what happens when you combine @code{-ls} and @code{-cat}:
			}

			figure {
				pre {= m4_fmt_code(ls-1.sh.gsp) }
			}

			p {-
				Ok… that looks about right.  We invoke @code{-ls} and we get a listing
				of the current directory, newline-separated.  Well look at what happens
				when we don’t compose it with another command:
			}

			figure {
				pre {= m4_fmt_code(ls-2.sh.gsp) }
			}

			p {-
				Yeah… it decided to ‘prettify’ the output by putting everything on one
				line.  If the input contains enough items it columnates them really
				nicely for you.  Here’s an example of what it looks like when I run
				@code{-ls} in my screenshots folder:
			}

			figure {
				pre {= m4_fmt_code(ls-3.sh.gsp) }
			}

			p {-
				Now don’t get me wrong, I like the fact that I can see more than one
				item per-line.  But why is this specific to @code{-ls}?  It could
				actually be really useful to be able to take arbitrary input and
				columnate it in such a form for easier consumption.  The @code{-column}
				program does exist on Linux systems, but it is far inferior to what
				@code{-ls} provides.  In the ideal world, @code{-ls} would simply
				display one filename per-line with a better @code{-column} command, and
				you could compose the two to get a nicer viewing experience for your
				files.
			}

			h3 {-Tabbed — Good}
			p {-
				What is one thing that almost all your graphical applications have in
				common?  They all have tabs.  Your web browser has tabs, your terminal
				probably supports tabs (and if it doesn’t, I bet you use @code{-tmux}).
				Your code editors have tabs, and even modern email-clients have tabs.
				Now let me ask you: why do we always reinvent the tab?
			}

			p {-
				Suckless — the same people that brought us @code{-dmenu} — also created
				a lesser-known application called @code{-tabbed}.  You can
				@a
					href="https://tools.suckless.org/tabbed/"
					target="_blank"
				{-find it here}.
				It’s quite a simple piece of software.  You simply run it together with
				another program (such as the @code{-st} terminal) and it adds
				tab-support to it.  Not only does this reduce code-duplication, but it
				also is benefitial for you the software user as it means you get a
				consistent UI with consistent-behavior and -key-bindings wherever you
				go.
			}
		}

		hr{}

		footer { m4_footer }
	}
}