T. Kurt Bond's µBlog, Computing Sub-Blog
2024-02-14T13:10:38-05:00
T. Kurt Bond
http://consp.org/blog/blog-computing-html.atom
Copyright © 2024 T. Kurt Bond
gmi-html-atom
Don't want the first line of a git commit COMMIT_EDITMSG buffer in Emacs to wrap?
http://consp.org/blog/2024/2024-02-14-dont-want-the-first-line-of-a-git-commit-commit-editmsg-buffer-in-emacs-to-wrap.html
2024-02-14T13:10:38-05:00
<main>
<h1>2024-02-14 13:10:38-05:00 - Don't want the first line of a git commit COMMIT_EDITMSG buffer in emacs to wrap?</h1>
<br/>
<p>Again, the trick is to use the Emacs variable fill-nobreak-predicate, but it's a bit trickier than my earlier example.</p>
<br/>
<p><a rel="noreferrer" href="http://consp.org/blog/2024/2024-01-21-dont-want-a-line-to-break-in-emacs-even-in-auto-fill-mode.html">Don't want a line to break in emacs even in auto-fill-mode?</a></p><br/>
<p>The code is very similar to the earlier code:</p>
<pre aria-label="">
(defun tkb-magit-commit-fill-nobreak-p ()
"Don't fill on the first line of a magit commit message."
(= 1 (line-number-at-pos)))
(defun tkb-magit-commit-find-file-hook ()
(interactive)
(when (string-match "COMMIT_EDITMSG\\'" (buffer-file-name))
(make-local-variable 'fill-nobreak-predicate)
(add-to-list 'fill-nobreak-predicate #'tkb-magit-commit-fill-nobreak-p)))
(add-to-list 'find-file-hook #'tkb-magit-commit-find-file-hook t)
</pre>
<br/>
<p>The problem is that, depending on where the new hook ends up in the list find-file-hook, it may run after the git-commit-setup-check-buffer find file hook. This is a problem because git-commit-setup-check-buffer runs git-commit-setup which runs normal-mode which runs kill-all-local-variables, which wipes out what our code was trying to do. Sigh.</p>
<br/>
<p>Instead, just specify the APPEND parameter to add-to-list as t:</p>
<pre aria-label="">
(add-to-list 'find-file-hook #'tkb-magit-commit-find-file-hook t)
</pre>
<p>This adds our hook function at the end of the list, hopefully after git-commit-setup-check-buffer.</p>
<br/>
<p>I've put this in a gist:</p>
<p><a rel="noreferrer" href="https://gist.github.com/tkurtbond/bf8c1b3dff4a1c56aeb43271726d276b">git-commit-fill-nobreak-predicate.el </a></p> </main>
Why Is Gnome So Annoyingly Useless?
http://consp.org/blog/2024/2024-01-21-why-is-gnome-so-annoyingly-useless.html
2024-01-21T20:28:24-05:00
<main>
<h1>2024-01-21 20:28:24-05:00 - Why Is Gnome So Annoyingly Useless?</h1>
<br/>
<p>The Gnome desktop seems to be removing more and more functionality, apparently in the name of “aesthetics” and simplicity. Unfortunately, they constantly make choices that are completely WRONG for the way I use computers. It's gotten so bad that in 2023 I switched to using KDE Plasma for my desktop on all my computers, after having gotten used to it on my Pinebook Pro, which comes with Manjaro ARM Linux with KDE Plasma. This improved my aggravation factor tremendously.</p>
<br/>
<p>But why is Gnome moving away from the functionality that computer developers want, a group that you'd think would be their prime target group?</p>
<br/>
<p>Well, I have heard it speculated that it's because Gnome is primarily developed by Redhat developers, and THEIR target group is not computer developers, but rather the users on government contracts where Gnome runs on machines that are used basically as specialized applications with some access to a few other minor applications. That target group, which may not use Gnome for anything else, would certainly benefit from simplicity.</p>
<br/>
<p>I don't think that Gnome should be the captive of a specific subset of users; it is, or should be, a general purpose desktop. If this isn't why Gnome has gone in this direction, I'll note that if they ARE doing it for some sort of aesthetic minimalism, similar to that which Apple vainly struggles for sometimes in macOS, it's still doing the wrong thing. I switched from an Apple laptop to a Linux laptop at work in 2023 as well, and find KDE Plasma and Linux a more pleasant environment in most ways. (If only the NVIDIA drivers were less flaky with multiple monitors. Sigh.)</p>
<br/>
<p><a rel="noreferrer" href="https://kde.org/plasma-desktop/">KDE Plasma Desktop</a></p><p><a rel="noreferrer" href="https://pine64.org/devices/pinebook_pro/">Pinebook Pro</a></p><p><a rel="noreferrer" href="https://manjaro.org/">Manjaro Linux</a></p> </main>
Putting all your emacs backups and autosaves in two directories has security implications
http://consp.org/blog/2024/2024-01-21-putting-all-your-emacs-backups-and-autosaves-in-two-directories-has-security-implications.html
2024-01-21T18:53:41-05:00
<main>
<h1>2024-01-21 18:53:41-05:00 - Putting all your emacs backups and autosaves in two directories has security implications</h1>
<br/>
<p>Recently, I noticed someone talking about putting all their emacs backups and autosaves in two directories, no matter where the file they are editing is located.</p>
<br/>
<p><a rel="noreferrer" href="gemini://idiomdrottning.org/bad-emacs-defaults">Bad Emacs defaults</a></p><br/>
<p>Their solution was:</p>
<pre aria-label="">
(setq auto-save-file-name-transforms '((".*" "~/.emacs_autosave/" t)))
(setq backup-directory-alist '(("." . "~/.emacs_backups/")))
</pre>
<br/>
<p>This has security implications when you are working with some filesystems that are encrypted and some that are not. If you are editing a file on a filesystem that is encrypted or removable (the secured filesystem), but the the autosave and backup directories are NOT on the secured filesystem, you've suddenly leaked information. Anybody who is working with their financial information or with their own or other folks' Personal Identifiable Information needs to consider this issue.</p>
<br/>
<p>If it IS a problem for you, I suggest something like this</p>
<pre aria-label="">
(setq backup-directory-alist '(("." . ".~/")))
(setq auto-save-file-name-transforms `((".*" ".~/" t)))
</pre>
<p>which collects those files for one directory into one sub-directory. This does mean you'll have multiple directories for those all over your drive, but its better than having then end up on unsecured media.</p>
<br/>
<p>If that doesn't work for your situation, and you REALLY need only one backup directory for the secured filesystem, you can use something like the following. Assume that the secured filesystem in mounted on /d1, and you have write permissions for the whole drive. (If you don't have write permissions for the whole drive, choose a directory that you do have write permissions for.) Then do the following:</p>
<pre aria-label="">
(setq backup-directory-alist '(("/d1/.*/." . "/d1/.~/")
("." . "~/.~/")))
</pre>
<p>The first item in backup-directory-alist makes all the backup files for files on /d1 end up in /d1/.~/, and the second item in that list the makes the backup files for other files end up in ~/.~/.</p>
<br/>
</main>
Don't want a line to break in emacs even in auto-fill-mode?
http://consp.org/blog/2024/2024-01-21-dont-want-a-line-to-break-in-emacs-even-in-auto-fill-mode.html
2024-01-21T15:03:08-05:00
<main>
<h1>2024-01-21 15:03:08-05:00 - Don't want a line to break in emacs even in auto-fill-mode?</h1>
<br/>
<p>Have you ever been editing a file in emacs where there a specific lines that should not be wrapped, but you are using auto-fill-mode and they accidently get wrapped? The emacs variable fill-nobreak-predicate is your friend!</p>
<pre aria-label="">
;; Nikola metadata lines start like this:
;; .. keyword:
;; They shouldn't tbe wrapped.
(defvar tkb-nikola-metadata-regexp "\\.\\. [a-z]+:")
(defun tkb-nikola-rest-fill-nobreak-p ()
"Don't fill on metadata lines in nikola reST posts."
(save-excursion
(beginning-of-line)
(looking-at tkb-nikola-metadata-regexp)))
(defun tkb-nikola-rest-hook ()
(interactive)
(when (and (string-match "\\.rst\\'" (buffer-file-name))
(looking-at tkb-nikola-metadata-regexp))
(make-local-variable 'fill-nobreak-predicate)
(setq fill-nobreak-predicate (list #'tkb-nikola-rest-fill-nobreak-p))))
(add-to-list 'find-file-hook #'tkb-nikola-rest-hook)
</pre>
<p><a rel="noreferrer" href="https://gist.github.com/tkurtbond/c4aa39ee5649688a34b10dc400cc858c">Here's a gist where you can comment on it.</a></p> </main>
Getting Emacs to Beep/Ding/Ring-the-Bell Again!
http://consp.org/blog/2023/2023-12-09-getting-emacs-to-beep-ding-ring-the-bell-again.html
2023-12-09T18:42:57-05:00
<main>
<h1>2023-12-09 18:42:57-05:00 - Getting Emacs to Beep/Ding/Ring-the-Bell Again!</h1>
<br/>
<p>Here's what I had to do to get Emacs to ring the bell again, under Fedora 39 and KDE:</p>
<pre aria-label="">
(defvar tkb-beep-sound "/usr/share/sounds/freedesktop/stereo/bell.oga")
(defvar tkb-beep-program "ogg123")
(defun tkb-bell ()
(interactive)
(start-process "Beep" nil tkb-beep-program
tkb-beep-sound))
(setq ring-bell-function #'tkb-bell)
(unless (file-exists-p tkb-beep-sound)
(yes-or-no-p (format "Error: tkb-beep-sound is set to \"%s\", which does \
not exist!\nUnderstand? "
tkb-beep-sound)))
(let ((path (split-string (getenv "PATH") ":")))
(unless (file-installed-p tkb-beep-program path)
(yes-or-no-p (format "Error: tkb-beep-sound is set to \"%s\", which does \
not exist!\nUnderstand? "
tkb-beep-program))))
</pre>
<br/>
<p><a rel="noreferrer" href="https://gist.github.com/tkurtbond/a79580b1a8a94e2f1f2c407efa1b0777">Here's a gist, where you can comment on it.</a></p><br/>
</main>
Programming Fonts
http://consp.org/blog/2023/2023-11-29-programming-fonts.html
2023-11-29T10:29:56-05:00
<main>
<h1>2023-11-29 10:29:56-05:00 - Programming Fonts</h1>
<br/>
<p>This is Emacs, displaying an enriched text file with text that I find useful for comparing fonts.</p>
<img loading="lazy" src="http://consp.org/blog/2023/emacs-ibm-plex-mono.png" alt="Emacs using the IBM Plex Mono font"></img><p><a rel="noreferrer" href="https://en.wikipedia.org/wiki/Enriched_text">Enriched text</a></p><br/>
<p>There are just an AMAZING way that fonts can be illegible or ugly. You owe it to yourself to go to the Programming Fonts website, put the characters that you care about in the second line of the code sample, which is empty, and work through the list until you find a font that delights and pleases the inner you! Download from there, unpack them, and put them in ~/.fonts/ on Linux, or some crazy place on macOS (~/Library/Fonts/? /Library/Fonts/?), and your life will improve too! Oh, you MS Windows users should do the appropriate thing on your … OS, as well.</p>
<br/>
<p><a rel="noreferrer" href="https://www.programmingfonts.org/">Programming Fonts</a></p><p><a rel="noreferrer" href="https://programmingfonts.tumblr.com/">Programming Fonts on Tumblr</a></p><p><a rel="noreferrer" href="https://github.com/braver/programmingfonts">Programming Fonts on GitHub</a></p> </main>
Pasting images into org-mode files from the clipboard
http://consp.org/blog/2023/2023-11-04-pasting-images-into-org-mode-files-from-the-clipboard.html
2023-11-04T16:01:12-04:00
<main>
<h1>2023-11-04 16:01:12-04:00 - Pasting images into org-mode files from the clipboard</h1>
<br/>
<p>I've long wanted to paste images into org-mode files as easy as one does with WYSIWYG editors. And today I figured out that you can do that with the org-download package and it's org-download-screenshot function! There was a helpful post at zzamboni.org that told how to do it on macOS. I adapted it to X and Wayland.</p>
<br/>
<p><a rel="noreferrer" href="https://github.com/abo-abo/org-download">org-download</a></p><p><a rel="noreferrer" href="https://zzamboni.org/post/how-to-insert-screenshots-in-org-documents-on-macos/">How to insert screenshots in Org documents on macOS </a></p><br/>
<p>If you are using Wayland, install the wl-clipboard package. If you are using X, install the xclip page.</p>
<br/>
<p>Then Install org-download and then use this config:</p>
<br/>
<pre aria-label="">
(use-package org-download
:after org
:defer nil
:custom
(org-download-method 'directory)
(org-download-image-dir "Images")
(org-download-heading-lvl nil)
(org-download-timestamp "%Y%m%d-%H%M%S_")
(org-image-actual-width 300)
:bind
("C-c k o d s" . org-download-screenshot)
:config
(require 'org-download)
(cond ((getenv "WAYLAND_DISPLAY")
;; check for Wayland first because of X on Wayland
(message "Wayland is here!")
(setq org-download-screenshot-method
"wl-paste > %s"))
((getenv "DISPLAY")
(message "X is here!")
(setq org-download-screenshot-method
"xclip -selection clipboard -t image/png -o > %s"))
(t
(message "Neither X nor Wayland are available."))))
</pre>
<br/>
<p>Here's an org-mode file I've just pasted some images into:</p>
<img loading="lazy" src="http://consp.org/blog/2023/paste-images-into-org-mode-files.png" alt="pasting into org-mode files screenshot"></img> </main>
Are C and C++ easier to learn than the Ada programming language?
http://consp.org/blog/2023/2023-10-10-are-c-and-c-easier-to-learn-than-the-ada-programming-language.html
2023-10-10T22:02:22-04:00
<main>
<h1>2023-10-10 22:02:22-04:00 - Are C and C++ easier to learn than the Ada programming language?</h1>
<br/>
<p>I often read people on the Internet opining that the Ada programming language is harder to learn that C and C++. I do not think that is true. I think learning to write incorrect programs in C and C++ is easier than learning Ada in general, but it is much easier to learn to write a correct program in Ada than in C and C++!</p>
<br/>
<p>Ada is a much more carefully designed and specified language and its design makes it a much safer programming language to learn to use correctly. An Ada programming writing a program will encounter more compile time errors, and need to think more about types, but in return will end up with a safer and easier to understand program.</p>
<br/>
<p>C and C++, on the other hand, have so many ways that the programming can shoot themselves in the foot, that it is very, very hard to ensure that all of a program is written correctly. Many things that would be caught at compile time in Ada are missed in C and C++. Easy to write an incorrect program, but incredibly difficult to ensure that a program is correct.</p>
<br/>
<p>I suspect that essentially all C and C++ are essentially incorrect. Certainly the prevalence of security problems and other bugs in C and C++ seems to support that.</p>
<br/>
<p>I think Ada is one programming language that more people should be exposed to. It is very well suited as a general purpose programming langauge, and a number of properties that also make it very well suited to mission critical and safety critical programs, with interesting features for formal definition and analysis, concurrent programming, real-time programming, and embedded programming.</p>
<br/>
<p><a rel="noreferrer" href="https://en.wikipedia.org/wiki/Ada_(programming_language)">Ada at Wikipedia</a></p><p><a rel="noreferrer" href="https://en.wikipedia.org/wiki/GNAT">GNAT, a free software Ada compiler</a></p><p><a rel="noreferrer" href="https://www.adacore.com/gnatpro">GNAT Pro, a commercially supported version of GNAT, from Adacore</a></p><p><a rel="noreferrer" href="https://alire.ada.dev/">Alire Ada source package manager</a></p><p><a rel="noreferrer" href="https://learn.adacore.com/">Adacore's resources for learning Ada</a></p><p><a rel="noreferrer" href="https://en.wikipedia.org/wiki/SPARK_(programming_language)">SPARK, the formally defined subset of Ada</a></p><p><a rel="noreferrer" href="https://learn.adacore.com/courses/Ada_For_The_Embedded_C_Developer/chapters/05_SPARK.html">Adacore learning resource on Enhancing Verification with SPARK and Ada</a></p><p><a rel="noreferrer" href="https://learn.adacore.com/courses/Ada_For_The_Embedded_C_Developer/chapters/03_Concurrency.html">Adacore learning resource on Concurrency and Real-Time</a></p><p><a rel="noreferrer" href="https://learn.adacore.com/courses/Ada_For_The_Embedded_C_Developer/chapters/04_Embedded.html">Adacore learning resource for Embedded Programming</a></p> </main>
How I Organize My Virtual Workspaces On My Desktop At Work
http://consp.org/blog/2023/2023-09-21-how-i-organize-my-virtual-workspaces-on-my-desktop-at-work.html
2023-09-21T10:57:07-04:00
<main>
<h1>2023-09-21 10:57:07-04:00 - How I Organize My Virtual Workspaces On My Desktop At Work</h1>
<br/>
<p>My primary virtual workspace on my desktop box at work running Fedora with the KDE Plasma desktop:</p>
<img loading="lazy" src="http://consp.org/blog/2023/oone-virtual-workspace-1.png" alt="Virtual Workspace 1: Work"></img><p>I have to overlap things a lot to fit everything on one screen.</p>
<br/>
<p>So, starting at the left top, (1) the first titlebar is gtimer, my tea timer program, and below that (2) is the titlebar of a 150x60 telnet logged into the VAX as user TKB running emacs. Below that (3) is my emacs on the Linux box, with a wheat background. Below that (2 again) is the bottom of that 150x60 telnet with user TKB running emacs, which is white on black, and actually has 3 frames open. Moving to the right (4) the white text on black window is an obsolete 150x60 telnet session to the VAX. (I just closed that one before sending this message). Next to the right (5) is a 150x60 telnet session to the VAX logged in as user TKBTEST and running emacs, which is black on white. (The TKBTEST account is used for developing and testing WEBMAIL_COMMUNICATOR, which is the system I'm currently trying to figure out.) Finally, moving to the right top, the window whose titlebar is showing (6) is a telnet session to the VAX for user TKB for running commands. Under that (7) is a black on white telnet session to the VAX as TKBTEST for running commands. Below that (6 again) is the white on black telnet session for TKB, then another (8) telnet for TKBTEST in black on white for running commands, then below that (9) is another white on black telnet session for TKB.</p>
<br/>
<p>I've got my telnet login sessions mirrored for TKB and TKBTEST because there are things I can't do in TKB that I can in TKBTEST and vice-versa: the application that I'm working on can only be edited and built using TKBTEST, but can only be installed to production using TKB. This particular set of windows is so I can work on that particular application. Normally, I'd just have the three windows for TKB.</p>
<br/>
<p>And yes, the VAX is an emulated VAX running in Charon-VAX and running VMS 5.5-2 (for hysterical raisins). I work with it almost every day, doing systems administration, software development, and providing support for customers.</p>
<br/>
<p>Usually I also have some terminal windows for working on the local machine, usually each with a couple of tabs. It was just chance that I didn't have any open today. And there is a hidden Virt Manager window along with a hidden window for the virtual machine console of the MS Windows 10 virtual machine it is running. I do most of my non VAX work using Unix machines, either macOS or Linux (though I've used and liked each of FreeBSD, NetBSD, and OpenBSD in the past, and have a couple of 32 bit NetBSD machines still), with the occasional unavoidable MS Windows work done in virtual machines.</p>
<br/>
<p>Then, if you look at the taskbar at the bottom, I've got 5 virtual workspaces. The first is the primary one for which I've shown the screenshot above, where I do most of my work.</p>
<br/>
<p>The second has Discord, Spotify, and some monitoring programs.</p>
<img loading="lazy" src="http://consp.org/blog/2023/oone-virtual-workspace-2.png" alt="Virtual Workspace 2: Instant Communications, Monitoring, Music"></img><br/>
<p>The third is where I have my Google Workspace windows in Chrome for work and in Firefox for my personal email.</p>
<img loading="lazy" src="http://consp.org/blog/2023/oone-virtual-workspace-3.png" alt="Virtual Workspace 3: Work and Personal Email"></img><p>Chrome has four tabs: (1) my HTML page of the links I commonly use, (2) Gmail, (3) Chat, and (4) Google Contacts. Firefox has six tabs: (1) my HTML page of links again, (2) Gmail, (3) Chat, (4) Google Contacts, (5) Google Calendar, and (6) Google Voice.</p>
<br/>
<p>The fourth is for transitory stuff and it doesn't have a standard list of windows, so I haven't taken a screenshot.</p>
<br/>
<p>The fifth has zuluCrypt, a couple of Dolphin (KDE's file manager) windows, and a Konsole (KDE's terminal app) window where I mount a directory from our NAS over SMB3, all used for copying the VAX backup tape files from the NAS to my external encrypted traveling drive.</p>
<img loading="lazy" src="http://consp.org/blog/2023/oone-virtual-workspace-5.png" alt="Virtual Workspace 5: Working with External Disks"></img><p>KeePassXC gets moved to this virtual workspace when I am mounting the external disk, because its password is stored in KeePassXC.</p>
<p>I do this every Monday through Friday, and then when I am at home I copy the tape files from the external traveling drive to another external encrypted drive on my desktop Fedora KDE Plasma machine there. The traveling external drive is encrypted with zuluCrypt, while the one at one is encrypted with LUKS. I use zuluCrypt on Linux because VeraCrypt on my macOS work laptop was not reliable for me; it crashed macOS a couple of times so I stopped using it.</p>
<br/>
<p>Anyhow, that's how I organize my virtual workspaces on oone, my Fedora KDE Plasma box at work. My setup on my Fedora KDE Plasma box at home is different because the screen is so much larger, but is similar. On my work macOS laptop I've got 21 virtual workspaces spread out over three monitors, and that's too much to go over right now.</p>
<br/>
</main>
I got STOIC running under CP/M using the RunCPM emulator!
http://consp.org/blog/2023/2023-07-09-i-got-stoic-running-under-cp-m-using-the-runcpm-emulator.html
2023-07-09T20:50:59-04:00
<main>
<h1>2023-07-09 20:50:59-04:00 - I got STOIC running under CP/M using the RunCPM emulator!</h1>
<br/>
<p>I'm using the RunCPM CP/M emulator.</p>
<br/>
<p><a rel="noreferrer" href="https://github.com/MockbaTheBorg/RunCPM">RunCPM CP/M Emulator</a></p><br/>
<p>Ok, I've got STOIC.COM built with the basic and miscellaneous words loaded. To do this, I assembled KERNEL.ASM to produce KERNEL.COM, ran KERNEL.COM, loaded the STOICBAS.STC and STOICMIS.STC files for the basic and miscellaneous words, used the SZSTOIC command to find out the number of 256 byte pages used by STOIC, exited STOIC with the RETCPM command, and then used the CP/M SAVE command to save the memory that STOIC was using to STOIC.COM, and then ran STOIC.COM to issue some STOIC commands. The "[" and "]" words are from the miscellaneous words from STOICMIS.STC, and count the number of items that are pushed on the stack between them.</p>
<br/>
<p>It went something like this:</p>
<br/>
<pre aria-label="">
RunCPM Version 6.1 (CP/M 60K)
A10>ASM KERNEL
CP/M ASSEMBLER - VER 2.0
1A98
00DH USE FACTOR
END OF ASSEMBLY
RunCPM Version 6.1 (CP/M 60K)
A10> KERNEL
0> 'STOICBAS CPMLD
0> 'STOICMIS CPMLD
0> SZSTOIC
STOIC IS 53 DECIMAL PAGES LONG
0> RETCPM
RunCPM Version 6.1 (CP/M 60K)
A10>SAVE 53 STOIC.COM
..........................................................................................................
A10>STOIC.COM
0> [ 1 2 3 4 ] = = = = =
4 4 3 2 1
0>
</pre>
<p>It seems this version of STOIC was never fully adapted to CP/M: apparently the file I/O and the editor weren't ported completely. I'll have to look into that.</p>
<br/>
<p>Whee! Isn't retrocomputing archaeology fun!</p>
<br/>
<p>I started with Volume 23 of the CP/M User Group disk archives, “STOIC (STACK ORIENTED INTERACTIVE COMPILER)”. Unfortunately, I could not find Volume 23B, which had other STOIC stuff.</p>
<br/>
<p><a rel="noreferrer" href="http://www.retroarchive.org/cpm/cdrom/SIMTEL/CPMUG/CPMUG023.ARK">CPMUG023.ARK</a></p><br/>
<p>I'm interested in STOIC because I used the VAX/VMS version back in the day.</p>
</main>
Getting the width of the current monitor in Emacs
http://consp.org/blog/2023/2023-06-27-getting-the-width-of-the-current-monitor-in-emacs.html
2023-06-27T13:02:39-04:00
<main>
<h1>2023-06-27 13:02:39-04:00 - Getting the width of the current monitor in Emacs</h1>
<br/>
<p>If you have virtual workspaces on macOS and you use the emacs function display-pixel-width it will give the combined with of ALL the monitors you are using. You are better off using (caddr (frame-monitor-attribute 'geometry)), since frame-monitor-attribute gets the specified attribute from the monitor which the current frame is actually on. BTW: The function frame-monitor-attributes returns all the monitor attributes. The function display-monitor-attributes-list returns the attributes for ALL the monitors you are using.</p>
<br/>
<p>I figured this out when I was debugging a couple of emacs functions to move the current frame left or right on the screen.</p>
<pre aria-label="">
(defun tkb-move-frame-left ()
"Move the current frame left by 1/10th the width of the physical montor."
(interactive)
(let* ((left (frame-parameter nil 'left))
(monitor-display-width (caddr (frame-monitor-attribute 'geometry)))
(tenth-width (/ monitor-display-width 10))
(new-left (- left tenth-width)))
(set-frame-parameter nil 'left new-left)))
(defun tkb-move-frame-right ()
"Move the current frame right by 1/10th the width of the physical montor."
(interactive)
(let* ((left (frame-parameter nil 'left))
(monitor-display-width (caddr (frame-monitor-attribute 'geometry)))
(tenth-width (/ monitor-display-width 10))
(new-left (+ left tenth-width)))
(set-frame-parameter nil 'left new-left)))
</pre>
</main>
Now available via gemini!
http://consp.org/blog/2023/2023-03-01-now-available-via-gemini.html
2023-03-01T23:01:40-05:00
<main>
<h1>2023-03-01 23:01:40-05:00 - Now available via gemini!</h1>
<br/>
<p>Previously this site has only been available as a blog on the World Wide Web.[1] But now it is also available as a gemini capsule![2]</p>
<p><a rel="noreferrer" href="http://consp.org">[1] consp.org on the WWW</a></p><p><a rel="noreferrer" href="gemini://consp.org">[2] consp.org in geminispace!</a></p> </main>
Using the Emacs Web Wowser to open URLs in Emacs
http://consp.org/blog/2023/2023-02-19-using-the-emacs-web-wowser-to-open-urls-in-emacs.html
2023-02-19T23:56:08-05:00
<main>
<h1>2023-02-19 23:56:08-05:00 - Using the Emacs Web Wowser to open URLs in Emacs</h1>
<br/>
<p>A couple of the computers I use have limited RAM (4 GiB), and Chrome and Firefox use up a lot of memory. So, sometimes I don't want to fire up an entire separate web browser, and since I'm almost always in Emacs anyway, I just use the Emacs Web Wowser, the web browser written in Emacs Lisp.</p>
<br/>
<p><a rel="noreferrer" href="https://www.gnu.org/software/emacs/manual/html_mono/eww.html">EWW, the Emacs Web Wowser</a></p><br/>
<p>Here are the functions I use to switch Emacs to using EWW by default to open URLs:</p>
<pre aria-label="">
(defun tkb-browse-url-eww (url &optional args)
"Invoke the eww browser (inside emacs) on URL. It the optional second
argument ARGS is true open in a new buffer."
(message "args: %S" args)
(eww url (and args 4)))
(defun tkb-toggle-eww ()
(interactive)
(cond ((eq browse-url-browser-function 'browse-url-default-browser)
(message "Switching to EWW for opening URLs.")
(setq browse-url-browser-function #'tkb-browse-url-eww))
(t
(message "Switching to browser-url-default-browser for opening URLs.")
(setq browse-url-browser-function #'browse-url-default-browser))))
</pre>
<p>You could do something similar using w3m.el, which uses the external text mode web browser w3m to render the HTML, but that doesn't (as far as I know) support images, and EWW does.</p>
</main>
Why use Scheme instead of Forth for creating Atom feeds?
http://consp.org/blog/2023/2023-02-19-why-use-scheme-instead-of-forth-for-creating-atom-feeds.html
2023-02-19T16:25:45-05:00
<main>
<h1>2023-02-19 16:25:45-05:00 - Why use Scheme instead of Forth for creating Atom feeds?</h1>
<p>Updated: 2023-03-02 13:52:49-05:00</p>
<br/>
<p>Despite admiring Forth, and having written an Forth-like language in the dim past, I have to admit that using Forth to parse and translate text with a complicated structure would be difficult for me, and I am more productive using CHICKEN Scheme for that. Forth's concrete nature and small size, which makes it very appropriate and helpful for some things, especially if you are building something from scratch and control the design of everything involved, but when working with existing complicated designs imposed from outside I find it helpful to use tools with more libraries.</p>
<br/>
<p>Some people in the Forth world think that you should always start from scratch. This gives you the greatest control over the software you are designing and implementing, and allows you to throw out many of the complications that you don't really need. However, when some of that complication is imposed from outside (the Atom Syndication Format, for instance, or HTML) it is helpful to use already written software if it is available and easier to use than writing your own from scratch.</p>
<br/>
<p>Lichen, the CMS this blog/site uses to render its Gemtext into HTML, does that: parsing Gemtext is very simple, and generating HTML from it is pretty easy, so using Forth works well. However, to generate Atom feeds you have to follow the rules for Subscribing to Gemini pages, which are pretty simple, and at least four RFCs (4287, 8288, 3339, and 3987), which are somewhat complicated. While generating the text of an Atom feed is simple, once you've got all the necessary data, to get that data you have to be able to do things like parse dates and HTML, select the interesting parts of the HTML, and re-encode the HTML with the proper escaping. </p>
<br/>
<p>If you look at the list of packages available in theForthNet's package manager (the only package manager I've found for Forth) there are 36 packages available, and they don't include any to deal with RFC 3339 Timestamps, parse HTML, select the proper parts of the HTML structure, manipulate them, and generate the HTML. No regular expression library, etc. When you look at the list of eggs (what CHICKEN Scheme calls its packaged libraries), there are 564 of them and they include lots of things I used to write the Atom feed generator for this blog/site.</p>
<br/>
<p><a rel="noreferrer" href="http://theforth.net/packages">theForthNet Forth packages</a></p><p><a rel="noreferrer" href="http://eggs.call-cc.org/5/">Eggs (packages) for CHICKEN Scheme 5</a></p><br/>
<p>I know there are 564 because, instead of counting by hand, like I did for the Forth pages at theForthNet, I wrote a 12 line CHICKEN Scheme program using two built-in libraries and three eggs that downloaded the web page that lists the CHICKEN Scheme eggs, parsed it into a Scheme version of XML, selected the relevant parts of the web page, and counted them. It took me about 10 or 15 minutes, most of which was looking at the API for the libraries and looking at the intermediate results to make sure I was looking at the right things.</p>
<br/>
<p>Here is the program:</p>
<pre aria-label=" parse-eggs-list.scm">
(import (chicken io))
(import (chicken port))
(import (html-parser))
(import (sxpath))
(import (http-client))
(define url "http://eggs.call-cc.org/5/")
(define eggs-page (with-input-from-request url #f read-string))
(define eggs-sxml (with-input-from-string eggs-page html->sxml))
(define eggs-urls ((sxpath '(// td a @ href *text*)) eggs-sxml))
(display (length eggs-urls))
(newline)
</pre>
<p>If there had been easily available Forth packages for things I needed to do I would probably have written the Atom feed generator in Forth. There WERE easily available CHICKEN Scheme packages for those things, so I used it instead.</p>
</main>
And now the Atom feeds have the content of the posts in the entries
http://consp.org/blog/2023/2023-02-10-and-now-the-atom-feeds-have-the-content-of-the-posts-in-the-entries.html
2023-02-10T13:20:23-05:00
<main>
<h1>2023-02-10 13:20:23-05:00 - And now the Atom feeds have the content of the posts in the entries</h1>
<p>Updated: 2023-02-21 12:55:54-05:00</p>
<br/>
<p>This way, when you look at an entry in a feed reader, it shows you the content of the blog post, instead of looking empty and requiring you to open the link to the content, however your feed reader does that. The content has a lot of vertical white space, which seems to be an unfortunate interaction between how I've been writing the gemtext of the blog and way the Lichen CMS, which I use to render the gemtext of the blog to HTML, does its conversion.</p>
<br/>
<p><a rel="noreferrer" href="https://lichen.sensorstation.co/">Lichen</a></p><p><a rel="noreferrer" href="https://gemini.circumlunar.space/docs/gemtext.html">gemtext </a></p><br/>
<p>Hmm. I'm beginning to think that its a idiosyncrasy of the way feed readers render the content, since web browsers render the HTML from which the content element is derived normally and without an unpleasant appearance. But why do ALL the feed readers I've tried have similar unpleasant renderings?</p>
<br/>
<p>Anyway, see the Colophon for how I did it.</p>
<br/>
<p><a rel="noreferrer" href="http://consp.org/Colophon.html">Colophon</a></p><br/>
</main>
Updated blog and Atom generator to use numeric time zone offsets
http://consp.org/blog/2023/2023-02-10-updated-blog-and-atom-generator-to-use-numeric-time-zone-offsets.html
2023-02-10T08:20:39-05:00
<main>
<h1>2023-02-10 08:20:39-05:00 - Updated blog and Atom generator to use numeric time zone offsets</h1>
<br/>
<p>It turns out that multiple locations use, colloquially, the same time zone abbreviations for different time zones. For instance, apparently, EST is used for part of the Americas and also for part of Australia. So I decided to eliminate that ambiguity and just use the numeric time zone offset in the headers on this blog. It makes generating the Atom feeds simpler.</p>
<br/>
<p>Oh, that's right; I've updated the blog and sub-blogs to have Atom feeds.</p>
<br/>
<p><a rel="noreferrer" href="https://en.wikipedia.org/wiki/Atom_(web_standard)">Atom Syndication Format</a></p><p><a rel="noreferrer" href="https://www.rfc-editor.org/info/rfc4287">RFC 4287 The Atom Syndication Format</a></p> </main>
Fuzzy Recollections of a Neat Capability of Unroff: file-insertions
http://consp.org/blog/2023/2023-02-07-fuzzy-recollections-of-a-neat-capability-of-unroff.html
2023-02-07T15:28:00-05:00
<main>
<h1>2023-02-07 15:28:00-05:00 - Fuzzy Recollections of a Neat Capability of Unroff: file-insertions </h1>
<br/>
<p>TKB: So, you know how you sometimes need to output something before the data you need to do it has been read from the input? So normally you save the input data in memory until you’ve read it all, then you find the information you need to output the early bit, then process the input data from memory to produce the output?</p>
<br/>
<p>CPB: Yep, I have been there before!</p>
<br/>
<p>TKB: But that is pain if you have to deal with large files and don’t have enough memory. Usually you’ve got more disk space than memory, so there is an interesting trick you can do instead that I learned from how Unroff (the roff translator written in Elk Scheme) handled cross references and tables of contents when converting to HTML. You don’t have the section titles for the table of contents or the names of the HTML files they’ll be in (because you’re chucking the output into multiple files) until you have read the whole document. So, just record the position in the file where the table of contents would go, and has you encounter sections record the section title and the output file it is in and then at the end of generating the files copy the file up to the point where the table of contents is, then output the table of contents with all the correct section titles and links to the output html files, and then copy the rest of the file. In fact, Unroff generalized to multiple files in such a way that you could record positions to use later in any file and add the necessary information no matter where in the input and output you were. Very useful!</p>
<br/>
<p>TKB: Back to unroff, I downloaded the source and groffed the manual, and see it is a little more primitive than I remembered. You used a stream-position function to record the output positions you were interested in, and added the filename, position, and text to be inserted to a list, and at the end of the program you passed all those to the file-insertions procedure (probably as the result of an exit event handler), which did all the rewriting. This was supported by the streams functionality: “Input, output, and storage of text lines in unroff are centered around a new Scheme data type named stream and a set of primitives that work on streams. A stream can act as a source (input stream) or as a sink (output stream) for lines of text. Streams not only serve as the basis for input and output operations and for the exchange of text with shell commands, but can also be used to temporarily buffer lines of text (e.g. foot- notes or tables of contents) and to implement user-defined macros in a simple way.”</p>
<br/>
<p>Unroff was written in Elk Scheme, which was a neat early Scheme. The versions from the original pages are still available, but may not run on modern Unixen. </p>
<br/>
<p><a rel="noreferrer" href="http://www-rn.informatik.uni-bremen.de/software/unroff/">Unroff Home Page</a></p><p><a rel="noreferrer" href="http://www-rn.informatik.uni-bremen.de/software/unroff/dist/unroff-1.0.tar.gz">Unroff Source</a></p><p><a rel="noreferrer" href="http://www-rn.informatik.uni-bremen.de/software/elk/">Elk Scheme: The Extension Language Kit</a></p><p><a rel="noreferrer" href="http://www-rn.informatik.uni-bremen.de/software/elk/dist.html">Elk: Distribution and Source Page</a></p><p><a rel="noreferrer" href="http://www-rn.informatik.uni-bremen.de/software/elk/dist/elk-3.0.tar.gz">Elk Source</a></p><br/>
<p>There is a newer version of Elk Scheme that may run on modern Unixen.</p>
<br/>
<p><a rel="noreferrer" href="http://sam.zoy.org/elk/">Elk Scheme - the Extension Language Kit, from Sam Voy</a></p><p><a rel="noreferrer" href="http://sam.zoy.org/elk/elk-3.99.8.tar.bz2">Prerelease: Elk Scheme 3.99.8</a></p><br/>
<p>Here are the manuals that come with Unroff in PDF:</p>
<br/>
<p><a rel="noreferrer" href="http://consp.org/files/unroff/unroff.1.pdf">unroff.1</a></p><p><a rel="noreferrer" href="http://consp.org/files/unroff/unroff-html-man.1.pdf">unroff-html-man.1</a></p><p><a rel="noreferrer" href="http://consp.org/files/unroff/manual.ms.pdf">manual.ms</a></p><p><a rel="noreferrer" href="http://consp.org/files/unroff/unroff-html.1.pdf">unroff-html.1</a></p><p><a rel="noreferrer" href="http://consp.org/files/unroff/unroff-html-ms.1.pdf">unroff-html-ms.1</a></p><br/>
</main>
How I Edit This Blog
http://consp.org/blog/2023/2023-02-06-How-I-Edit-This-Blog.html
2023-02-06T22:16:00-05:00
<main>
<h1>2023-02-06 22:16:00-05:00 - How I Edit This Blog</h1>
<p>Updated: 2023-06-27 10:00:24-04:00</p>
<br/>
<p>I use GNU Emacs, of course.</p>
<p><a rel="noreferrer" href="https://www.gnu.org/software/emacs/">GNU Emacs</a></p><p>The file tkb-microblog.el contains everything I wrote to support editing these blog posts:</p>
<p><a rel="noreferrer" href="https://github.com/tkurtbond/microblog/blob/main/emacs/tkb-microblog.el">tkb-microblog.el </a></p><p>When I execute the tkb-microblog function it prompts me for the blog post title, then asks what sub-blogs I want to add it to, if any. Then it adds a link to the new blog post file to the main blog index and each of the sub-blog indexes I specified, creating them if necessary.</p>
<br/>
<p>The function tkb-find-file-hook makes sure that I edit gemtext files (which end in .gmi) with visual-line-mode on and auto-fill-mode off, because gemini browsers wraps long lines, unless they are preformatted text, and paragraphs are indicated by newlines. (Blank lines add space between paragrahs.) I also have a minor mode that rebinds M-q (which is normally bound to fill-paragraph) to a function that tells the user not to do that, because the lines are not supposed to be filled.</p>
<br/>
<p>Anyway, I think it works well.</p>
<br/>
<p>Amusingly, right now tkb-microblog.el is 131 lines, about 26% the size of the Lichen CMS, at 494 lines, that I use to render the gemtext of this blog to HTML.</p>
<p><a rel="noreferrer" href="https://lichen.sensorstation.co/">Lichen</a></p> </main>