Paolo Amoroso's Journal

lisp

The end of the work on WebCard marked the completion of my RetroChallenge 2024 project, in time as hoped.

I accomplished the initial goal of extending NoteCards to visit websites. This is my Linux desktop after traversing a NoteCards link to a Web card which opened the associated URL in Firefox:

A website opened in Firefox by traversing a Web card link with WebCard.

As the RetroChallenge encourages to do I learned a lot, shared my experience, and had lots of fun with retro stuff.

WebCard is not my first NoteCards project but helped me explore other features of the system, particularly the definition of new types of cards. Most of the work on WebCard involved researching the NoteCards API and writing code.

Once I understood the relevant API calls, implementing the planned features took relatively little code. NoteCards comes with an extensive, well designed and documented API that enables to add a lot of functionality by mostly plugging into the public hooks.

The NoteCards manual has nearly all the information I needed. However, to understand some features or subtle points of the API I had to study some of the NoteCards code, particularly the source that defines the File card type because of the similarities with what WebCard does. Some throwaway code and experimentation with the interactive Lisp environment plugged the last information gaps.

The project generated a flow of material for my blog and Mastodon profile. I posted frequent short updates on Mastodon and longer reports on the blog. This drained time and focus too.

The main takeaway of the project is that Medley Interlisp is a rich toolbox with which new programs can be developed by combining other programs as building blocks. NoteCards itself builds upon the TEdit text editor, the Sketch line drawaing program, the File Browser, and other tools.

As my first RetroChallenge I was lucky to complete the project. I set a goal reasonably achievable in one month but the actual work faced some unexpected detours that didn't impact the deadline.

What else to say? Mission accomplished.

#WebCard #Interlisp #Lisp

Discuss... Email | Reply @amoroso@fosstodon.org

To complete WebCard for my RetroChallenge 2024 project I created a demo notefile, a file that stores the data of a NoteCards hypertext.

The notefile WCDEMO.NOTEFILE contains exmples of Web cards filed into various types of containers and cards such as fileboxes and Text cards. It provides some ready made Web cards for exploring WebCard.

This screenshot shows the main cards of the demo notefile:

The cards of a WebCard notefile open in NoteCards.

The link icons with the globe bitmap at the left of the outlined text are links to Web cards. Clicking such a link in NoteCards opens the associated URL in a web browser, which is the main feature of WebCard.

#WebCard #Interlisp #Lisp

Discuss... Email | Reply @amoroso@fosstodon.org

With the last feature of WebCard behind me I proceeded with the next task to wrap up my RetroChallenge 2024 project: documenting the system.

Since WebCard enhances NoteCards with only a few simple but significant features a full manual would be overkill. So I added to the README file of the project repo some new sections on the requirements and dependencies, the installation, and the usage of WebCard.

The documentation assumes familiarity with NoteCards and Medley Interlisp, large systems in themselves, and describes only what WebCard adds to NoteCards. It explains how to create and manage Web cards and traverse links to them.

In addition the README file now has a screenshot that shows a website opened by WebCard in NoteCards.

#WebCard #Interlisp #Lisp

Discuss... Email | Reply @amoroso@fosstodon.org

NoteCards link icons leading to cards of a certain type can and typically do have a custom bitmap associated with the type.

WebCard cards of type Web initially inherited the bitmap of the parent type Text, a stylized NoteCards blank card frame. To visually differentiate links to Web cards I added a new bitmap, here open in the bitmap editor of Medley Interlisp:

The bitmap of WebCard cards of type Web in the bitmap editor of Medley Interlisp.

The bitmap at its actual size of 21x18 pixels is near the top left corner of the window. It represents a blank card frame with at the center a globe crossed by meridians and parallels, a common symbol of web links.

Aside from some misunderstandings on defining Interlisp bitmaps, adding a bitmap to WebCard was easy.

Once designed and defined the bitmap itself I passed it as the value of the LinkIconAttachedBitMap property along wiht the other arguments of NCP.CreateCardType, the NoteCards API function that defines new card types.

The hard part was coming up with a suitable bitmap, which kept me busy on and off for a couple of weeks.

As an artistically clueless geek my original plan was to pick a public domain icon, scale it to the required size, and import it in Medley Interlisp. Although this Lisp environment predates most modern image file formats, Andrew Sengul wrote a Lisp tool that can convert from PBM to the native Interlisp bitmap format.

I soon found a nice globe icon. Then I was unwillingly thrown into a rabbit hole of NetPBM, Gimp, and ImageMagick tools and options, struggling to produce the right format Andrew's tool could process.

I learned the hard way that if an image contains only black and white pixels, and no other colors, it's unnecessarily difficult to obtain a black and white, 1-bit depth file. Most tools save to 8-bit grayscale despite claiming to do 1-bit black and white.

When I finally imported the rescaled, converted PNG into Medley I realized it was an unlegible tiny blob.

Link icon bitmaps have a size of 21x18 pixels and, aside from the stylized card that makes up the frame of the bitmap, the usable area is only a dozen pixels across. In desperation I fired up the Medley Interlisp bitmap editor and designed the bitmap myself from scratch. It took just a few minutes and was unexpectedly easy.

I'm pleased with the result, but stunned at how long such a seemingly simple task dragged me.

#WebCard #Interlisp #Lisp

Discuss... Email | Reply @amoroso@fosstodon.org

Over the past days I ran WebCard a bit, reviewed the code, and checked my notes and I'm satisfied with what the system does. Since WebCard is nearly feature complete it's a good time to chart the next steps for wrapping up my RetroChallenge 2024 project.

Aside from some tweaks or cleanups, the only other code to write will set a bitmap for the link icon of Web cards. This is useful to further visually distinguish them from other types of cards such as Text.

WebCard also needs some documentation. I'll expand the README file to explain how to install and use WebCard. A demo notefile with examples of Web cards in a NoteCards hypertext is also useful to show what WebCard does.

#WebCard #Interlisp #Lisp

Discuss... Email | Reply @amoroso@fosstodon.org

WebCard has very limited control over the web browser of the host operating system.

It can only command the browser to visit a URL when the user traverses a Web link or executes the Visit URL menu command. But with no precautions the browser would open a new tab for every visit of the same URL.

To reduce clutter I tweaked WebCard to keep track of visited URLs. The URLVisitedP boolean property of a Web card window indicates whether the associated URL was already visited. The function WCD.TraverseWebLink checks URLVisitedP and visits the URL only if the property is NIL, then sets it to T if it does visit the URL. URLVisitedP is a property of the window rather than the card because, as part of the dynamic session state, NoteCards shouldn't save it in notefiles.

The overall behavior of Web cards and URL visits appears as follows.

Traversing the link of a closed Web card unconditionally visits the URL. Once the card is open, traversing the link again flashes the card to call attention to it but doesn't visit the URL. The Visit URL menu command can force the visit though. Closing a card sets URLVisitedP to NIL, so the next time link traversal reopens the card it triggers a visit.

This should take care of the most common cases of unintentional link traversal, reduce tab clutter, and prepare WebCard for actual usage.

#WebCard #Interlisp #Lisp

Discuss... Email | Reply @amoroso@fosstodon.org

In NoteCards, Text cards are rectangular windows with proportions similar to a post-it note. The Web card type of WebCard inherits from Text, including the default window size. Since a Web card needs only display a URL, the default shape leaves most of the text area blank.

To make Web cards better fit the text area and visually differentiate them from cards of other types I reduced the default height to slighly less than half. The text of a Web card now has enough vertical space for three lines of a wrapped URL. The change makes Web cards closer to badges or tags with a URL as a label than a textual note.

To see the result compare the Web card at the top with the Text card a the bottom:

A Web (top) and a Text card (bottom) in WebCard.

I made other changes to WebCard, some of which related to the new card shape. First, the WCD.UpdateCardText function now scrolls the card window back to the top to ensure the initial portion of the URL is always in view.

Next, I modified WCD.ValidURLP to check that the lenght of the input URL doesn't exceed 255 characters, the maximum a card property can hold.

Finally, I completed the initialization of Web cards in WCD.MakeWebCard to handle cards that are not immediately displayed upon creation. This is the case of a Web card created via the NoteCards API when the nodisplayflg parameter of NCP.CreateCard is non NIL, instead of interactively by the user. I factored out the code common to displayed and undisplayed cards into the separate function WCD.InitCard.

It took me longer than expected to understand the initialization flow of undisplayed cards. My early attempts produced errors about a missing TEdit window as I unknowingly skipped the initialization of the parent Text type. Calling the parent constructor resolved the issue.

#WebCard #Interlisp #Lisp

Discuss... Email | Reply @amoroso@fosstodon.org

I fixed a URL validation bug of WebCard I have been stuck with for almost a week.

When creating a new card, the function WCD.AskURL brings up a dialog and loops prompting for a URL to go with the card until the input is valid. After the fix the input dialog looks like this, here shown above a new blank card. I entered https, the dialog warned it's not a valid URL, and then I typed a correct one.

URL input dialog of WebCard.when creating a new Web card.

WCD.AskURL initially checked only for a null input. I later wrote WCD.ValidURLP to check that the input resembles a URL.

In an attempt to call WCD.ValidURLP from the WCD.AskURL input loop I bumped into a syntax error in the bind clause of an Interlisp iterative statement. The issue eluded me when staring at the code for long. Then the problem suddenly jumped at me: a missing symbol.

The bug is now fixed for good and I can move on.

#WebCard #Interlisp #Lisp

Discuss... Email | Reply @amoroso@fosstodon.org

The text of WebCard cards is intended to be read only but my previous attempt to achieve it by overriding card editing didn't work. I implemented a new, simpler approach that actually works.

The card type Web inherits from the Text type whose “substance” is a text stream associated with the TEdit editor embedded in Text cards. In NoteCards a substance is a data structure that contains the information in the card.

The trick of the new approach is to just make the text stream of the card read only.

An additional complication is that the read only state is a runtime property of open streams not preserved in saved notefiles. Therefore, if in a new session you load a notefile, any previously read only cards it stores will no longer be so. To catch this WebCard now intercepts the first access to an unopened Web card, which occurs when clicking a link icon to the card. I modified WCD.TraverseWebLink to set the text to read only.

If the user clicks the text area of a Web card and starts typing, a dialog informs that the text is read only. The Close option of the right-click menu dismisses the dialog.

A number of WebCard functions display the URL of a Web card in its text area. Since the code for inserting the text and handling the modification state was scattered and partially duplicated in various places, I factored it out into the new function WCD.UpdateCardText. It sets the card text to read-write, clears the existing text, inserts the new text, and makes the text read only again.

#WebCard #Interlisp #Lisp

Discuss... Email | Reply @amoroso@fosstodon.org

A URL is associated with a WebCard card of type Web at creation time but it may later be necessary to change or take action on the URL. For example, to correct a typo or visit the URL again if its web browser tab was closed since an earlier visit.

For such situations I added the items Visit URL and Edit URL to the title bar menu of Web cards. This is the menu:

A WebCard card of type Web with its left-click title bar menu.

The card holds the URL shown in the text area. Left-clicking on the title bar brings up the menu with the new items Visit URL and Edit URL at the top.

The NoteCards API function NCP.AddTitleBarMenuItemsToType adds items to the menu of a specified card type. It's easy to use but it wasn't clear to me what arguments the item callback functions are supposed to take. Some experimentation with throwaway code revealed the system passes only one argument to callbacks, a window.

To prepare for the new functionality I factored out the initialization of the Web card type into the function WCD.InitWebCard that also calls NCP.AddTitleBarMenuItemsToType.

Functions WCD.VisitURLMenuCmd and WCD.EditURLMenuCmd carry out the actual menu actions and are straightfoward. In addition to updating the URL property of the card, WCD.EditURLMenuCmd substitutes the new URL for the old in the text area.

#WebCard #Interlisp #Lisp

Discuss... Email | Reply @amoroso@fosstodon.org