summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSacha Chua <sacha@sachachua.com>2021-11-28 10:21:32 -0500
committerSacha Chua <sacha@sachachua.com>2021-11-28 10:21:32 -0500
commitfee6e9625143b4595ada6709a8ee2a3e2dee1297 (patch)
tree4904e5ed508cd13dbb0c3e69bbec84da3626cd45
parent3c7e2842aec25f76d7fdc706e5d72ce619995726 (diff)
downloademacsconf-wiki-fee6e9625143b4595ada6709a8ee2a3e2dee1297.tar.xz
emacsconf-wiki-fee6e9625143b4595ada6709a8ee2a3e2dee1297.zip
Update
Diffstat (limited to '')
-rw-r--r--2021/captions/emacsconf-2021-ui--yak-shaving-to-a-ui-framework-help-i-accidentally-yak-shaved-my-way-to-writing-a-ui-framework-because-overlays-were-slow--erik-anderson--main.vtt634
1 files changed, 634 insertions, 0 deletions
diff --git a/2021/captions/emacsconf-2021-ui--yak-shaving-to-a-ui-framework-help-i-accidentally-yak-shaved-my-way-to-writing-a-ui-framework-because-overlays-were-slow--erik-anderson--main.vtt b/2021/captions/emacsconf-2021-ui--yak-shaving-to-a-ui-framework-help-i-accidentally-yak-shaved-my-way-to-writing-a-ui-framework-because-overlays-were-slow--erik-anderson--main.vtt
new file mode 100644
index 00000000..7ee41c3a
--- /dev/null
+++ b/2021/captions/emacsconf-2021-ui--yak-shaving-to-a-ui-framework-help-i-accidentally-yak-shaved-my-way-to-writing-a-ui-framework-because-overlays-were-slow--erik-anderson--main.vtt
@@ -0,0 +1,634 @@
+WEBVTT
+
+00:07.600 --> 00:00:09.120
+Hi! I'm Erik Anderson,
+
+00:00:09.120 --> 00:00:10.559
+and I'll be talking about tui,
+
+00:00:10.559 --> 00:00:11.840
+a user interface framework
+
+00:11.840 --> 00:00:15.040
+that I've written in Emacs Lisp.
+
+00:15.040 --> 00:00:16.196
+First, I want to talk a bit about
+
+00:00:16.196 --> 00:00:17.296
+the problem space of
+
+00:00:17.296 --> 00:00:18.728
+user interface development,
+
+00:00:18.728 --> 00:00:20.880
+specifically, I want to quickly illustrate
+
+00:00:20.880 --> 00:00:22.320
+some of the complexities involved
+
+00:00:22.320 --> 00:00:26.480
+with UI implementation in Emacs.
+
+00:26.480 --> 00:00:27.920
+In Emacs, we have the ubiquitous
+
+00:00:27.920 --> 00:00:29.920
+buffer object type that forms the container
+
+00:00:29.920 --> 00:00:31.920
+for most content in Emacs.
+
+00:00:31.920 --> 00:00:34.079
+Most interfaces we interact with
+
+00:00:34.079 --> 00:00:36.239
+consist of character based content
+
+00:00:36.239 --> 00:00:38.239
+in a buffer that's presented
+
+00:00:38.239 --> 00:00:40.079
+in a window in frame.
+
+00:40.079 --> 00:00:41.520
+Although the underlying content
+
+00:00:41.520 --> 00:00:44.320
+may be textual, Emacs has capable APIs
+
+00:00:44.320 --> 00:00:47.680
+to present rich content.
+
+00:47.680 --> 00:00:49.200
+The pervasiveness of buffers
+
+00:00:49.200 --> 00:00:50.879
+affords us wonderful flexibility.
+
+00:00:50.879 --> 00:00:52.559
+This presentation, for instance,
+
+00:00:52.559 --> 00:00:55.520
+is running in an Emacs buffer.
+
+00:55.520 --> 00:00:57.420
+Using Emacs's built-in basic
+
+00:00:57.420 --> 00:00:59.199
+button library, we can insert
+
+00:00:59.199 --> 00:01:00.884
+an interactive button
+
+00:01:00.884 --> 00:01:01.760
+that shows a message
+
+00:01:01.760 --> 00:01:06.080
+in the minibuffer when clicked.
+
+01:06.080 --> 00:01:09.200
+What about UIs that express application state?
+
+01:09.200 --> 00:01:11.439
+Most applications don't have a static UI.
+
+01:11.439 --> 00:01:13.280
+As application state changes,
+
+00:01:13.280 --> 00:01:14.320
+the UI should change
+
+00:01:14.320 --> 00:01:18.479
+to display the desired content.
+
+01:18.479 --> 00:01:20.320
+One simplifying strategy is to simply
+
+01:20.320 --> 00:01:23.600
+re-render the entire UI upon any change.
+
+01:23.600 --> 00:01:25.680
+First erase the contents of the buffer,
+
+01:25.680 --> 00:01:27.600
+and then reinsert your UI again
+
+00:01:27.600 --> 00:01:29.040
+with desired changes,
+
+00:01:29.040 --> 00:01:33.040
+and restore things like point and region.
+
+01:33.040 --> 00:01:34.560
+Basic composition is possible
+
+00:01:34.560 --> 00:01:35.759
+with this approach.
+
+00:01:35.759 --> 00:01:37.200
+Simply insert the elements
+
+00:01:37.200 --> 00:01:39.280
+of the UI in sequence.
+
+01:39.280 --> 00:01:40.640
+Complex elements can be
+
+00:01:40.640 --> 00:01:44.320
+composed of multiple sub-elements.
+
+01:44.320 --> 00:01:45.840
+UIs can be made extensible,
+
+00:01:45.840 --> 00:01:47.040
+and expose this composition,
+
+00:01:47.040 --> 00:01:49.360
+for example, with insertion hooks
+
+00:01:49.360 --> 00:01:52.320
+like magit's status sections hook.
+
+01:52.320 --> 00:01:54.159
+This generally relies on elements
+
+00:01:54.159 --> 00:01:56.640
+being well-behaved inserting themselves,
+
+00:01:56.640 --> 00:02:00.399
+not affecting the rest of the buffer.
+
+02:00.399 --> 00:02:02.960
+If we find ourselves with complex UIs,
+
+02:02.960 --> 00:02:04.640
+large buffers, long lines,
+
+00:02:04.640 --> 00:02:06.320
+or poor rendering performance,
+
+00:02:06.320 --> 00:02:09.039
+we might consider partial UI updates
+
+00:02:09.039 --> 00:02:11.360
+rather than re-rendering completely.
+
+02:11.360 --> 00:02:12.800
+In that case, the complexity
+
+00:02:12.800 --> 00:02:15.840
+for maintaining the UI quickly increases.
+
+00:02:15.840 --> 00:02:17.360
+As accessible as buffers are,
+
+00:02:17.360 --> 00:02:19.120
+we don't have high level abstractions
+
+00:02:19.120 --> 00:02:20.879
+for managing portions of a UI
+
+00:02:20.879 --> 00:02:22.160
+rendered to a buffer.
+
+00:02:22.160 --> 00:02:23.520
+(It) is left up to the programmers
+
+00:02:23.520 --> 00:02:25.440
+to track and update UI state.
+
+00:02:25.440 --> 00:02:26.540
+This is generally done by
+
+00:02:26.540 --> 00:02:28.959
+one of two methods, reflection,
+
+00:02:28.959 --> 00:02:30.800
+searching for strings or text properties
+
+00:02:30.800 --> 00:02:34.239
+within the buffer, or tracking segments
+
+00:02:34.239 --> 00:02:36.080
+of a UI buffer manually
+
+00:02:36.080 --> 00:02:38.959
+using numeric offsets, or marker,
+
+00:02:38.959 --> 00:02:45.280
+or overlay objects.
+
+02:45.280 --> 00:02:47.280
+Here we have a basic timer component
+
+02:47.280 --> 00:02:48.720
+that shows elapsed time
+
+00:02:48.720 --> 00:02:50.319
+after it's inserted.
+
+00:02:50.319 --> 00:02:52.160
+It works, but has several problems.
+
+00:02:52.160 --> 00:02:55.519
+It doesn't restore the user's point or mark,
+
+02:55.519 --> 00:02:59.120
+so it snaps back after every render,
+
+02:59.120 --> 00:03:01.040
+after every update.
+
+03:01.040 --> 00:03:03.360
+It relies on singleton global state,
+
+00:03:03.360 --> 00:03:05.124
+so isn't designed to coexist
+
+00:03:05.124 --> 00:03:12.000
+with other instances of itself.
+
+03:12.000 --> 00:03:13.200
+It doesn't use a marker,
+
+00:03:13.200 --> 00:03:14.640
+so it's sensitive to content
+
+00:03:14.640 --> 00:03:16.239
+proceeding it, that's following it,
+
+00:03:16.239 --> 00:03:23.519
+changing in the buffer.
+
+03:23.519 --> 00:03:25.120
+The update logic doesn't even consider
+
+03:25.120 --> 00:03:26.799
+which buffer it's trying to update.
+
+00:03:26.799 --> 00:03:27.840
+If I switch buffers,
+
+00:03:27.840 --> 00:03:29.360
+it will insert into another buffer,
+
+00:03:29.360 --> 00:03:31.519
+or even the minibuffer.
+
+03:31.519 --> 00:03:33.360
+It can't remove itself, or re-render
+
+00:03:33.360 --> 00:03:34.879
+if it gets corrupted, as you see.
+
+00:03:34.879 --> 00:03:35.920
+All in all, it's not
+
+00:03:35.920 --> 00:03:38.400
+a readily composable component.
+
+03:38.400 --> 00:03:39.519
+Addressing these components
+
+00:03:39.519 --> 00:03:41.920
+within this logic further increases
+
+00:03:41.920 --> 00:03:43.936
+the implementation complexity
+
+00:03:43.936 --> 00:03:45.680
+of this component,
+
+00:03:45.680 --> 00:03:46.640
+and still this component
+
+00:03:46.640 --> 00:03:47.280
+would likely have
+
+00:03:47.280 --> 00:03:49.120
+various subtle differences
+
+03:49.120 --> 00:03:52.480
+with other components
+
+00:03:52.480 --> 00:03:58.959
+implemented by other authors.
+
+03:58.959 --> 00:04:00.319
+For those of you unfamiliar
+
+00:04:00.319 --> 00:04:02.159
+with this term Yak Shaving,
+
+00:04:02.159 --> 00:04:04.080
+that is a quite technical term
+
+00:04:04.080 --> 00:04:07.599
+for any seemingly pointless activity,
+
+00:04:07.599 --> 00:04:09.680
+which is actually necessary
+
+00:04:09.680 --> 00:04:10.879
+to solve a problem,
+
+04:10.879 --> 00:04:11.920
+which solves a problem,
+
+00:04:11.920 --> 00:04:14.799
+which, several levels of recursion later,
+
+04:14.799 --> 00:04:18.239
+solves the real problem you're working on.
+
+04:18.239 --> 00:04:19.943
+The itch that led to this project
+
+00:04:19.943 --> 00:04:21.840
+was the desire to display a dense summary
+
+00:04:21.840 --> 00:04:24.400
+of local Git repository statuses.
+
+04:24.400 --> 00:04:26.560
+Encountering various implementation
+
+04:26.560 --> 00:04:30.080
+complexity for building UI elements,
+
+04:30.080 --> 00:04:31.680
+it led to the yak shaving endeavor
+
+00:04:31.680 --> 00:04:33.680
+that produced tui.
+
+04:33.680 --> 00:04:35.440
+When I wrote the library,
+
+04:35.440 --> 00:04:36.479
+I had recently played with
+
+00:04:36.479 --> 00:04:39.360
+a popular UI framework called React,
+
+00:04:39.360 --> 00:04:41.840
+and had an interest in learning
+
+00:04:41.840 --> 00:04:44.080
+about the internal architecture of React.
+
+00:04:44.080 --> 00:04:45.680
+So, rather than implement
+
+00:04:45.680 --> 00:04:46.960
+a string caching layer
+
+00:04:46.960 --> 00:04:49.280
+on top of tabulated list mode,
+
+00:04:49.280 --> 00:04:50.360
+I was rather inclined
+
+00:04:50.360 --> 00:04:52.400
+to go down the path of implementing
+
+00:04:52.400 --> 00:04:58.960
+the React API for Emacs Lisp.
+
+04:58.960 --> 00:05:00.896
+I'll offer a brief view of
+
+00:05:00.896 --> 00:05:05.120
+the tui Emacs Lisp API.
+
+05:05.120 --> 00:05:07.360
+Inserting component content
+
+00:05:07.360 --> 00:05:08.320
+is pretty straightforward.
+
+00:05:08.320 --> 00:05:10.160
+You take a component tree
+
+00:05:10.160 --> 00:05:16.240
+and render it in an Emacs buffer.
+
+05:16.240 --> 00:05:18.639
+If any elements in that tree are updated,
+
+05:18.639 --> 00:05:21.039
+their respective content on the tree
+
+00:05:21.039 --> 00:05:26.320
+is updated automatically.
+
+05:26.320 --> 00:05:27.919
+Here's a basic re-implementation
+
+00:05:27.919 --> 00:05:29.919
+of the straw man timer from earlier,
+
+00:05:29.919 --> 00:05:32.400
+using a macro for syntactic trigger.
+
+05:32.400 --> 00:05:34.404
+You'll notice that
+
+00:05:34.404 --> 00:05:36.164
+the signature includes its own
+
+00:05:36.164 --> 00:05:44.560
+object reference, arguments, and state.
+
+05:44.560 --> 00:05:46.400
+Associating arguments in the state
+
+05:46.400 --> 00:05:51.360
+with a component instance out of the box,
+
+05:51.360 --> 00:05:54.400
+makes it easy to design reusable components,
+
+00:05:54.400 --> 00:06:06.080
+and forms the basis for partial UI updates.
+
+06:06.080 --> 00:06:07.840
+The component rendering anchors
+
+00:06:07.840 --> 00:06:09.199
+are durable, so content can be
+
+00:06:09.199 --> 00:06:11.360
+added and removed surrounding content,
+
+00:06:11.360 --> 00:06:12.479
+or even within the region
+
+00:06:12.479 --> 00:06:13.280
+of the component,
+
+00:06:13.280 --> 00:06:16.319
+and replaced when it re-renders.
+
+06:16.319 --> 00:06:17.600
+Components will also
+
+00:06:17.600 --> 00:06:20.880
+cleanly remove themselves from a buffer
+
+00:06:20.880 --> 00:06:28.400
+when instructed to.
+
+06:28.400 --> 00:06:30.160
+tui contains the core implementation
+
+00:06:30.160 --> 00:06:33.440
+of the React API, so components,
+
+06:33.440 --> 00:06:35.840
+their constituent props, state,
+
+00:06:35.840 --> 00:06:38.000
+and all of the lifecycle methods
+
+00:06:38.000 --> 00:06:39.440
+associated with them,
+
+06:39.440 --> 00:06:41.120
+as well as keys, refs,
+
+00:06:41.120 --> 00:06:43.228
+and the fundamental
+
+00:06:43.228 --> 00:06:47.520
+reconciliation algorithm of React.
+
+06:47.520 --> 00:06:52.188
+A variety of other React APIs
+
+00:06:52.188 --> 00:06:58.080
+that haven't been implemented yet.
+
+06:58.080 --> 00:07:00.080
+It contains some useful features so far,
+
+07:00.080 --> 00:07:02.639
+such as hot reloading, reflection,
+
+00:07:02.639 --> 00:07:06.164
+and various debugging tools,
+
+00:07:06.164 --> 00:07:12.639
+and some reconciliation logging.
+
+07:12.639 --> 00:07:14.880
+Lastly, I'd like to give you some quick
+
+07:14.880 --> 00:07:19.039
+visual taste of components built with tui.
+
+07:19.039 --> 00:07:20.240
+The grid view that motivated
+
+00:07:20.240 --> 00:07:21.520
+my development of this package
+
+00:07:21.520 --> 00:07:23.039
+is very similar to Magit's
+
+00:07:23.039 --> 00:07:30.720
+list repositories functionality.
+
+07:30.720 --> 00:07:36.080
+Essentially, tabulated list mode
+
+07:36.080 --> 00:07:39.440
+but portable and has a separated model
+
+00:07:39.440 --> 00:07:49.360
+and presentation layers.
+
+07:49.360 --> 00:07:51.840
+Here's a basic xkcd comic viewer
+
+00:07:51.840 --> 00:08:07.360
+showing a couple classics.
+
+08:07.360 --> 00:08:10.080
+A long-standing React tutorial is
+
+08:10.080 --> 00:08:13.280
+building a tic-tac-toe game
+
+08:13.280 --> 00:08:14.879
+as a bit of a gimmick,
+
+08:14.879 --> 00:08:17.039
+and I'm not quite satisfied with
+
+00:08:17.039 --> 00:08:25.599
+the buffering direction,
+
+00:08:25.599 --> 00:08:27.120
+but it got me thinking about
+
+00:08:27.120 --> 00:08:28.639
+layout engines with text,
+
+00:08:28.639 --> 00:08:35.120
+so it was interesting.
+
+08:35.120 --> 00:08:38.560
+And here's a small
+
+00:08:38.560 --> 00:08:46.080
+Unicode character viewer
+
+08:46.080 --> 00:08:55.279
+capable of showing a bunch of characters.
+
+08:55.279 --> 00:08:57.279
+If this piques your interest,
+
+00:08:57.279 --> 00:08:59.200
+I would encourage you to check it out.
+
+08:59.200 --> 00:09:01.440
+tui should be usable by anyone
+
+00:09:01.440 --> 00:09:04.640
+with some basic Elisp familiarity,
+
+09:04.640 --> 00:09:09.680
+no prior knowledge about JavaScript
+
+00:09:09.680 --> 00:09:12.080
+or React is necessary.
+
+09:12.080 --> 00:09:13.732
+I'd absolutely love to talk with people
+
+00:09:13.732 --> 00:09:14.880
+about the tui package,
+
+00:09:14.880 --> 00:09:17.440
+textual user interfaces in general,
+
+00:09:17.440 --> 00:09:19.040
+and really anything in Emacs.
+
+00:09:19.040 --> 00:09:20.693
+If you have any ideas, feedback,
+
+00:09:20.693 --> 00:09:21.680
+or want to contribute,
+
+00:09:21.680 --> 00:09:23.360
+please reach out.
+
+09:23.360 --> 00:09:24.360
+Thank you all for listening.
+
+00:09:24.360 --> 00:09:27.000
+[captions by bhavin192 (Bhavin Gandhi)]