Eev and Squeak
I'm trying to learn Squeak (Wikipedia). I am mostly following the book "Squeak by Example" and the Swiki, but I am also trying to adapt some of the main ideas of eev to Squeak. My super-messy notes on Squeak are here.
1. Elisp hyperlinks, but in Squeak
Eev is a tool for taking "executable notes", and usually this consists on two parts: 1) recording all commands that we send to "shell-like programs" (this is explained here), and 2) saving hyperlinks to everything interesting that we find. In Squeak the idea (1) only applies to things like (re)installing Squeak itself, and the idea (2) needs to be adapted: eev implements it with many kinds elisp hyperlinks, that are one-liners that start with "find-", and I'm translating some elisp hyperlink to "Squeak hyperlinks", that are one-liners that start with "See", like these ones:
2. Three kinds of elisp hyperlinks
In eev I use three kinds of elisp hyperlinks. In
the one with `find-sh' opens its target in another buffer in the same Emacs window, the one with `find-sh0' displays its result in the echo area, and the one with `find-xpdf-page' calls xpdf and displays a PDF in another window, outside Emacs.
In 2023feb09 I sent this question to the mailing list. It contained this block of "executable notes", intended to be used from inside a workspace:
Some of its lines will only do something interesting it we run a "print it" on them, some lines are to be run with "do it"s, and some of the lines create external windows or morphs when executed... so: three kinds. Note that the block above doesn't use the class See!
3. The class "See"
You can install my class "See", together with two helper classes called "HelpBrowserB" and "EdrxGuideHelp", by downloading the .st file below from the link below - the .st.html is an htmlized version produced with engrave-faces,
and then using the Tools → File List and the "fileIn" button. Then try to run "See see". I need to rewrite the rest of this section!
You can download my class "See" as a .st file here, and you can see a version of it htmlized with engrave-faces here. I am a very beginner-ish beginner, so my code is 1) very primitive at several points, and 2) very ugly everywhere.
Some of the methods of my class "See" are "detached menu entries". For example, here is the method that "See methodFinder" runs:
The "ECToolSet openSelectorBrowser" in the last line does the same as this sequence of mouse clicks:
I discovered that the "action" of "World menu → open → method finder" is "ECToolSet openSelectorBrowser" by doing this:
The expression "See item1tsa: self" returns the fields "contents", "target", "selector", and "arguments" of the result of "self submorphs at: 1". Sometimes it returns a 4-uple that is easy to convert to an executable expression, like in this screenshot, that corresponds to the example above:
4. Squeaky targets
...but sometimes "See item1ctsa: self" returns something that I don't know - yet - how to "translate to code". Here's an example. One of the entries of the menu "Help" has the label "Squeak Help". The result of "See item1ctsa: self" on that entry is this:
Here the "target" field is an object of the class "TheWorldMainDockingBar". The "The" in that name suggests that usually there is at most one "main docking bar" in the "world", but I don't know how to write an expression that can be run from anywhere and that will return "the" main docking bar when one exists...
Let me call these "targets" that are hard to rebuild running global code "Squeaky targets". I come from Emacs-land, in which practically all actions are easy to "translate to code", so handling "Squeaky targets" is still a bit hard for me.
In 2023feb01 I sent this question to the mailing list, and Marcel Taeumel answered this. I was able to apply his idea to some menu items, but not to all (yet); the code in the next section was inspired by some of his suggestions.
5. Storing squeaky targets
A reasonable workaround is to store "squeaky targets" in a globally accessible place. Remember that the use of "real" global variables in SmallTalk is frowned upon, and remember if you have two workspaces and you run "foo := 42" in the first of them, then you won't be able to access that variable in the second workspace... also, inspectors and debuggers have mini-workspaces.
Here's what I did. I defined a class variable called "Store" in my class "See", and I defined these four accessor methods for it:
Then I could initialize the global storage with this,
and I could use these methods to transport squeaky targets from a debugger to my main workspace. For example, I could open a debugger on the search bar and run "See at: #sb put: self" there, and then on my main workspace I would do "sb := See at: #sb" to copy that search bar object to a variable with a very short name - "sb" - that is local to that workspace.
6. Methods for morphic
I also added to my class "See" five class methods to help me capture keyboard events and send these events to morphs. Here are their definitions, without comments:
Due to my beginerishness I had to spend many days, and several e-mails to the mailing list, to write the methods above. The next two sections have examples of how I use them.
7. Using "addAlarm:after:"
Try this in a workspace:
For more context, see this thread in the mailing list: 1, 2, 3, 4, 5, 6. The method "run:after:" of my class "See" uses the ideas of the posts 4 and 5. Note that some people have suggested other ways to run code after a "sleep 5", but I'm using the first solution that worked.
8. Capturing and re-sending keyboard events
This is my current favorite way (in 2023feb24) of capturing and re-sending keyboard events:
It is super-tricky. The variable "save" works as an Lvalue, and after, say, "save := [ :evt | foo := evt ]", running "save value: 42" stores 42 in the variable "foo", that is local to my main workspace. Each line of this block needs to be run with a separate "do it",
and after running each one the keyboard focus will be transfered to the red rectangle at the top left of the screen. After the "do it" on the first one you have to type a CR on the rectangle, then go back to the workspace; then run a "do it" on the second one, and type an <up>, and go back to the workspace; then run the third with a "do it", type a <down>, and go back to the workspace. Then run a "print it" on this,
to check that the variables "cr", "up", and "down" now contain the correct keyboard events. After checking that, run this,
and click on the search bar - before 5000ms - to transfer the keyboard focus to it; the block "[ sb := See keyboardFocus ]" will be run after these 5000ms, and it will save a submorph of the search bar into the variable "sb". After that run a "print it" on the line with "sb" to check that the variable sb contains an object of the class TextMorphForEditView, and then you can try "do it"s on these lines
to send a CR to the search bar; the first one simply sends the CR, and the second one runs a "self halt" before sending the CR, and this lets us see in the debugger what is the code that a CR in the search bar runs.
9. See edrxGuide
In the two one-liners below,
the first one opens the "Terse Guide to Squeak", and the second one opens the "Edrx Guide to Squeak". The edrxGuide is implemented in two classes, and you can examine them with:
Anyway, here are some links to my super-messy notes on Squeak: