Irreal: Using Pcase and Name-let for Pattern Matching and Tail Recursion

Erik L. Arneson has an interesting post about using functional programming constructs with Elisp. In particular, he considers pattern matching and tail recursion.

Tail recursion is, in my estimation, one of the most useful properties a programming language can have. Scheme famously has it in its specification and many Lisps have it de facto if not de jure. If you’re not used to using recursion in your programming, that may seem like hyperbole but once you’ve internalized the method, other paradigms seem clumsy. Tail recursion is not really built into Elisp but it’s still possible using the named-let construct. It’s basically the same as Scheme’s named-let so if you’re a Schemer you’ll feel right at home.

Sadly, I haven’t internalized the pattern matching paradigm although I keep promising myself to do so. It’s a powerful idea that extends things like C’s switch statement or Lisp’s cond and case constructs. In Elisp, you use the pcase construct for this. Once you get used to the pattern syntax, it’s a powerful generalization of the common “if-else” constructs most programming languages have.

Arneson’s examples don’t begin to capture the power of these methods. They’re powerful tools that are well worth learning and internalizing. If you’re an Emacser, Elisp provides you an easy way of experimenting with these techniques. Believe me, mastering them will make you a better programmer.

-1:-- Using Pcase and Name-let for Pattern Matching and Tail Recursion (Post jcs)--L0--C0--November 27, 2022 06:54 PM

Bozhidar Batsov: Reading Files in OCaml

One thing I’ve noticed on my journey to learn OCaml was that reading (text) files wasn’t as straightforward as with many other programming languages. To give you some point of reference - here’s how easy it is to do this in Ruby:

# read entire file to string
content = File.read(filename)

# read lines into an array of lines
lines = File.readlines(filename)

# process lines one at a time (memory efficient when dealing with large files)
File.foreach(filename) { |line| puts line }

In my beloved Clojure the situation is similar:

;; read entire file into string
(slurp filename)

;; process lines one at a time
(use 'clojure.java.io)

(with-open [rdr (reader filename)]
  (doseq [line (line-seq rdr)]
    (println line)))

Basically there are three common operations when dealing with text files:

  • reading the whole contents as a single string
  • reading the whole contents of a collection of lines (often that’s just a slight variation of the previous operation)
  • reading and processing lines one by one (useful when dealing with large files)

When I had to play with files in OCaml for the first time I did some digging around and I noticed that many people were either rolling out their own read_lines function based on the built-in input_line function or using Jane Street’s Base library.

(* Using Base *)
open Core.Std
let contents = In_channel.read_all file
let lines = In_channel.read_lines file

(* homemade read_lines that gathers all lines in a list *)
let read_lines name : string list =
  let ic = open_in name in
  let try_read () =
    try Some (input_line ic) with End_of_file -> None in
  let rec loop acc = match try_read () with
    | Some s -> loop (s :: acc)
    | None -> close_in ic; List.rev acc in
  loop []

lines = read_lines filename

(* homemade read_lines that processes each line *)
let read_lines file process =
  let in_ch = open_in file in
  let rec read_line () =
    let line = try input_line in_ch with End_of_file -> exit 0
    in (* process line in this block, then read the next line *)
       process line;
       read_line ();
in read_line ()

read_lines some_file print_endline

Obviously, this gets the job done, but I was quite surprised such basic operations are not covered in the standard library. Turns out, however, that the situation has changed recently with OCaml 4.14 with the introduction of the module In_channel:1

(* read the entire file *)
let read_file file =
  In_channel.with_open_bin file In_channel.input_all

(* read lines *)
let read_lines file =
  let contents = In_channel.with_open_bin file In_channel.input_all in
  String.split_on_char '\n' contents

List.iter print_endline (read_lines filename)

While you still need to roll out your own read_file and read_lines functions, the implementation is significantly simpler than before. Even more importantly, the code is now more reliable as noted by Daniel Bünzli:2

Be careful, input_line is a footgun and has led to more than one bug out there – along with open_in and open_out defaulting to text mode and thus lying by default about your data.

input_line will never report an empty final line and performs newline translations if your channel is in text mode. This means you can’t expect to recover the exact file contents you just read by doing String.concat "\n" on the lines you input with input_line.

Also of course it doesn’t help with making sure you correctly close your channels and don’t leak them in case of exception. The new functions finally make that a no brainer.

You can also use In_channel.input_line to read file contents line by line and avoid excessive memory allocation. I’m still missing something like Clojure’s line-seq that create a lazy seq from which you can obtain the file lines, but I guess this should be doable in OCaml one way or another.3

I encourage everyone to peruse the documentation of In_channel to learn more about the functions it offers and the advantages of using it over the legacy input_line function.

I really wish that someone would update OCaml’s page on file manipulation to include coverage of the OCaml 4.14 functionality (perhaps I’ll do this myself). I’m guessing this outdated page and other legacy docs are sending a lot of people in the wrong direction, which was the main reason I’ve decided to write this article.

That’s all I have for you today. Keep hacking!

-1:-- Reading Files in OCaml (Post Bozhidar Batsov (bozhidar@batsov.net))--L0--C0--November 27, 2022 07:52 AM

Irreal: Viewing Exotic Image Files

As you know, Emacs can display most of the common image formats such as SVG, JPEG, PNG, and GIF but what about formats, such as webp, that aren’t handled natively by Emacs? Álvaro Ramírez has another quickie that tells us how to do it.

It turns out to be simple, especially if you already have ImageMagick or one of a couple of other external image converters already on your system, it’s just a matter of telling Emacs to use the external image converter. Here’s the magic spell:

(setq image-use-external-converter t)

If you don’t already have ImageMagick installed, you might find it a worthwhile addition to your system. Previously, Ramírez considered the problem of combining a series of JPEGs into a single PDF and told us how to do that. His solution was in the context of his dwim-shell-command framework but it’s just a simple call to ImageMagick’s convert command. Many of his simple DWIM Emacs shell functions make use of ImageMagick so you might also want to consider adding dwim-shell-command to your Emacs configuration.

Ramírez has been blogging up a storm lately. Many of his posts offer actionable suggestions for solving the small but annoying problems that we all run into. If you haven’t already, you may want to add his feed to your RSS reader.

-1:-- Viewing Exotic Image Files (Post jcs)--L0--C0--November 26, 2022 06:50 PM

Emacs Redux: Editing Links in org-mode

Links in org-mode by default are displayed as “descriptive” links, meaning they hide their target URLs (or a destination in general). While this looks great, it makes it a bit tricky to figure out how you can edit their URL. There are two easy options:

  1. Just press C-c C-l (org-insert-link) while your point is within a link and you’ll be prompted to edit its URL in the minibuffer. You can use the same command to create new links (when your point is not on an existing link).

  2. You can convert the “descriptive” links to “literal” links1 by invoking the command M-x org-toggle-link-display. You can also toggle between the two display modes for links via the mode’s menu (under “Hyperlinks”).

And that’s all I have for you today. Admitted, I keep forgetting about this all the time, as I rarely use org-mode, which is the reason I’ve decided to write this short article. Keep hacking!

  1. As a reminder - org-mode links have the format [[URL][DESCRIPTION]]

-1:-- Editing Links in org-mode (Post Bozhidar Batsov)--L0--C0--November 26, 2022 10:01 AM

Protesilaos Stavrou: Emacs: my new ‘altcaps’ package

The altcaps package helps you apply alternating letter casing to convey sarcasm or mockery. For example, convert this:

I respect the authorities

To this:

i ReSpEcT tHe AuThOrItIeS

The altcaps package thus makes you more effective at textual communication. Plus, you appear sophisticated. tRuSt Me.

Use any of the following commands to achieve the desired results:

  • altcaps-word :: Convert word to alternating letter casing. With optional NUM as a numeric prefix argument, operate on NUM words forward, defaulting to 1. If NUM is negative, do so backward. When NUM is a negative prefix without a number, it is interpreted -1.

  • altcaps-region :: Convert region words between BEG and END to alternating case. BEG and END are buffer positions. When called interactively, these are automatically determined as active region’s boundaries, else the space between mark and point.

  • altcaps-dwim :: Convert to alternating letter casing Do-What-I-Mean style. With an active region, call altcaps-region. Else invoke altcaps-word with optional NUM, per that command’s functionality (read its documentation).


-1:-- Emacs: my new ‘altcaps’ package (Post)--L0--C0--November 26, 2022 12:00 AM

Jiacai Liu: Oh My GitHub 1.0 is out!

I'm glad to announce my package Oh My GitHub v1.0 is out. Besides bug fixes, it introduce a very practical feature: create pull request without leaving Emacs. AFAIK, there already exists a similar package called github-pullrequest does this job, but its interface is not very flexible, the PR's title and description is hard coded, and this will break template setup by owners if there exists one. In oh-my-github, M-x omg-pull-create will open an org-mode buffer to edit what a PR required:
-1:-- Oh My GitHub 1.0 is out! (Post)--L0--C0--November 26, 2022 12:00 AM

Irreal: Red Meat Friday: eMacs

You guys always jump on me and accuse me of being cantankerous when I go off on a rant like this but, really, it’s too much to bear. I’ve noticed lately that some people are referring to Emacs as “eMacs” as if Emacs stood for “electronic macs”, or “electronic macros”, or something. It doesn’t. Emacs is widely understood to stand for “Editing MACroS”, although Irreal’s go to guy for Emacs history, Lars Brinkhoff, says he can find no evidence for that. Regardless, the E certainly does not stand for “electronic” so if you’re going to write about Emacs, can you please name it correctly and not make it look like a marketing term?

Yes, yes. I know it’s a small thing and hardly worth commenting on but names do matter and it’s important to get them right. Otherwise, as with the word “hacker”, the ignorant will kidnap the term and change its meaning. Don’t let that happen to our beloved editor. Fight this abomination whenever and wherever it raises its ugly head.

Added before publication: Perhaps this explains it.

-1:-- Red Meat Friday: eMacs (Post jcs)--L0--C0--November 25, 2022 05:32 PM

Irreal: macOS As A Unix Workstation

Torstein K. Johansen has an interesting post on configuring a Mac to be comfortable for a Linux user. Johansen is a self described “die hard Linux user” but recently had to work on a Mac. Macs are Unix machines but they’re based on FreeBSD and are certainly not Linux so if you’re a Linux user it’s useful to know how to configure a Mac to be as much like a Linux workstation as possible.

The most important thing, of course, is getting a decent Emacs installed. It used to be that Apple included Emacs in their distributions but it was a very old version and not one that any modern day user would want to use. They’ve since stopped including it so you’ve no choice but to install your own. I do that by compiling from source but Johansen chose to load his from Homebrew.

Once Emacs is installed, most of the rest of Johansen’s configuration involves replacing the default, older, BSD Unix utilities with their more up to date GNU versions. His post shows how to do all that.

We here at Irreal are, as most of you know, a Mac shop so we don’t have that problem but Johansen’s post is still worthwhile. For example, I learned about btop, a top replacement and used his recipe to install it. I’m content with the BSD versions of the Unix utilities but if you prefer the GNU versions, he shows you how to install them.

All in all, its a really useful post for anyone who wants to make their Mac the best possible workstation. Macs are famously Unix based but the default install hides a lot of that from you. Johansen shows you how to fix that.

-1:-- macOS As A Unix Workstation (Post jcs)--L0--C0--November 24, 2022 07:25 PM

T. V. Raman: Announcing Emacspeak 57.0 (Tilden)

Announcing Emacspeak 57.0—Tilden!

Tilden

Easy things are often amusing and relaxing, but their value soon fades. Greater pleasure, deeper satisfaction, and higher wages are associated with genuine accomplishments, with the successful fulfillment of a challenging task. –Donald Knuth

1. For Immediate Release:

San Jose, CA, (November 23, 2022)

1.1. Emacspeak 57.0 (Tilden) Unleashed! 🦮

— Making Accessible Computing Effortless!

Advancing Accessibility In The Age Of User-Aware Interfaces — Zero cost of Ownership makes priceless software Universally affordable!

Emacspeak Inc (NASDOG: ESPK) — http://github.com/tvraman/emacspeak announces immediate world-wide availability of Emacspeak 57.0 (Tilden) 🦮 — a powerful audio desktop that leverages today's evolving Data, Social and Assistant-Oriented Internet cloud to enable working efficiently and effectively from anywhere!

2. Investors Note:

With several prominent tweeters (and mythical elephants) expanding coverage of #emacspeak, NASDOG: ESPK has now been consistently trading over the social net at levels close to that once attained by DogCom high-fliers—and is trading at levels close to that achieved by once better known stocks in the tech sector.

3. What Is It?

Emacspeak is a fully functional audio desktop that provides complete eyes-free access to all major 32 and 64 bit operating environments. By seamlessly blending live access to all aspects of the Internet such as ubiquitous assistance, Web-surfing, blogging, remote software development, social computing and electronic messaging into the audio desktop, Emacspeak enables spoken access to local and remote information with a consistent and well-integrated user interface. A rich suite of task-oriented tools provides efficient speech-enabled access to the evolving assistant-oriented social Internet cloud.

4. Major Enhancements:

  1. Speech server for software DECTalk. 📢
  2. Learn Smarter By Taking Rich, Hypertext Notes. 🏫
  3. Integrated Youtube player using mpv. 📹
  4. Leverage Emacs Repeat-Mode to minimize chording. ⌨
  5. Speech-Enable NotMuch mail. 📪
  6. Screen brightness with module light. 🔅
  7. Emacspeak Auditory Display Under Pulseaudio 🔊
  8. Speciality browsers for various types of bookmarks. 📑
  9. Sounds Themes Using OGG. ℗

    — And a lot more than will fit this margin. … 🗞

Note: This version requires emacs-28.1 or later.

5. Establishing Liberty, Equality And Freedom:

Never a toy system, Emacspeak is voluntarily bundled with all major Linux distributions. Though designed to be modular, distributors have freely chosen to bundle the fully integrated system without any undue pressure—a documented success for the integrated innovation embodied by Emacspeak. As the system evolves, both upgrades and downgrades continue to be available at the same zero-cost to all users. The integrity of the Emacspeak codebase is ensured by the reliable and secure Linux platform and the underlying GIT versioning software used to develop and distribute the system.

Extensive studies have shown that thanks to these features, users consider Emacspeak to be absolutely priceless. Thanks to this wide-spread user demand, the present version remains free of cost as ever—it is being made available at the same zero-cost as previous releases.

At the same time, Emacspeak continues to innovate in the area of eyes-free Assistance and social interaction and carries forward the well-established Open Source tradition of introducing user interface features that eventually show up in luser environments.

On this theme, when once challenged by a proponent of a crash-prone but well-marketed mousetrap with the assertion "Emacs is a system from the 70's", the creator of Emacspeak evinced surprise at the unusual candor manifest in the assertion that it would take popular idiot-proven interfaces until the year 2070 to catch up to where the Emacspeak audio desktop is today. Industry experts welcomed this refreshing breath of Courage Certainty and Clarity (CCC) at a time when users are reeling from the Fear Uncertainty and Doubt (FUD) unleashed by complex software systems backed by even more convoluted press releases.

6. Independent Test Results:

Independent test results have proven that unlike some modern (and not so modern) software, Emacspeak can be safely uninstalled without adversely affecting the continued performance of the computer. These same tests also revealed that once uninstalled, the user stopped functioning altogether. Speaking with Aster Labrador, the creator of Emacspeak once pointed out that these results re-emphasize the user-centric design of Emacspeak; “It is the user — and not the computer– that stops functioning when Emacspeak is uninstalled!”.

6.1. Note from Aster,Bubbles and Tilden:

UnDoctored Videos Inc. is looking for volunteers to star in a video demonstrating such complete user failure.

7. Obtaining Emacspeak:

Emacspeak can be downloaded from GitHub — see https://github.com/tvraman/emacspeak you can visit Emacspeak on the WWW at http://emacspeak.sf.net. You can subscribe to the emacspeak mailing list — emacspeak@emacspeak.org. The Emacspeak Blog is a good source for news about recent enhancements and how to use them.

The latest development snapshot of Emacspeak is always available at GitHub.

8. History:

  • Emacspeak 57.0 is named in honor of Tilden Labrador.
  • Emacspeak 56.0 (AgileDog) belies its age to be as agile as Tilden.
  • Emacspeak 55.0 (CalmDog) attempts to be as calm as Tilden.
  • Emacspeak 54.0 (EZDog) learns to take it easy from Tilden.
  • Emacspeak 53.0 (EfficientDog) focuses on efficiency.
  • Emacspeak 52.0 (WorkAtHomeDog) makes working remotely a pleasurable experience.
  • Bigger and more powerful than any smart assistAnt, AssistDog provides

instant access to the most relevant information at all times.

  • Emacspeak 50.0 (SageDog) embraces the wisdom of stability as opposed to rapid change and the concomitant creation of bugs.🚭: Naturally Intelligent (NI)™ at how information is spoken, Emacspeak

is entirely free of Artificial Ingredients (AI)™.

  • Emacspeak 49.0 (WiseDog) leverages the wisdom gleaned from earlier releases to provide an enhanced auditory experience.
  • Emacspeak 48.0 (ServiceDog) builds on earlier releases to provide continued end-user value.
  • Emacspeak 47.0 (GentleDog) goes the next step in being helpful while letting users learn and grow.
  • Emacspeak 46.0 (HelpfulDog) heralds the coming of Smart Assistants.
  • Emacspeak 45.0 (IdealDog) is named in recognition of Emacs' excellent integration with various programming language environments — thanks to this, Emacspeak is the IDE of choice for eyes-free software engineering.
  • Emacspeak 44.0 continues the steady pace of innovation on the audio desktop.
  • Emacspeak 43.0 brings even more end-user efficiency by leveraging the ability to spatially place multiple audio streams to provide timely auditory feedback.
  • Emacspeak 42.0 while moving to GitHub from Google Code continues to innovate in the areas of auditory user interfaces and efficient, light-weight Internet access.
  • Emacspeak 41.0 continues to improve on the desire to provide not just equal, but superior access — technology when correctly implemented can significantly enhance the human ability.
  • Emacspeak 40.0 goes back to Web basics by enabling efficient access to large amounts of readable Web content.
  • Emacspeak 39.0 continues the Emacspeak tradition of increasing the breadth of user tasks that are covered without introducing unnecessary bloatware.
  • Emacspeak 38.0 is the latest in a series of award-winning releases from Emacspeak Inc.
  • Emacspeak 37.0 continues the tradition of delivering robust software as reflected by its code-name.
  • Emacspeak 36.0 enhances the audio desktop with many new tools including full EPub support — hence the name EPubDog.
  • Emacspeak 35.0 is all about teaching a new dog old tricks — and is aptly code-named HeadDog in on of our new Press/Analyst contact. emacspeak-34.0 (AKA Bubbles) established a new beach-head with respect to rapid task completion in an eyes-free environment.
  • Emacspeak-33.0 AKA StarDog brings unparalleled cloud access to the audio desktop.
  • Emacspeak 32.0 AKA LuckyDog continues to innovate via open technologies for better access.
  • Emacspeak 31.0 AKA TweetDog — adds tweeting to the Emacspeak desktop.
  • Emacspeak 30.0 AKA SocialDog brings the Social Web to the audio desktop—you can't but be social if you speak!
  • Emacspeak 29.0—AKAAbleDog—is a testament to the resilliance and innovation embodied by Open Source software—it would not exist without the thriving Emacs community that continues to ensure that Emacs remains one of the premier user environments despite perhaps also being one of the oldest.
  • Emacspeak 28.0—AKA PuppyDog—exemplifies the rapid pace of development evinced by Open Source software.
  • Emacspeak 27.0—AKA FastDog—is the latest in a sequence of upgrades that make previous releases obsolete and downgrades unnecessary.
  • Emacspeak 26—AKA LeadDog—continues the tradition of introducing innovative access solutions that are unfettered by the constraints inherent in traditional adaptive technologies.
  • Emacspeak 25 —AKA ActiveDog —re-activates open, unfettered access to online information.
  • Emacspeak-Alive —AKA LiveDog —enlivens open, unfettered information access with a series of live updates that once again demonstrate the power and agility of open source software development.
  • Emacspeak 23.0 — AKA Retriever—went the extra mile in fetching full access.
  • Emacspeak 22.0 —AKA GuideDog —helps users navigate the Web more effectively than ever before.
  • Emacspeak 21.0 —AKA PlayDog —continued the Emacspeak tradition of relying on enhanced productivity to liberate users.
  • Emacspeak-20.0 —AKA LeapDog —continues the long established GNU/Emacs tradition of integrated innovation to create a pleasurable computing environment for eyes-free interaction.
  • emacspeak-19.0 –AKA WorkDog– is designed to enhance user productivity at work and leisure.
  • Emacspeak-18.0 –code named GoodDog– continued the Emacspeak tradition of enhancing user productivity and thereby reducing total cost of ownership.
  • Emacspeak-17.0 –code named HappyDog– enhances user productivity by exploiting today's evolving WWW standards.
  • Emacspeak-16.0 –code named CleverDog– the follow-up to SmartDog– continued the tradition of working better, faster, smarter.
  • Emacspeak-15.0 –code named SmartDog–followed up on TopDog as the next in a continuing series of award-winning audio desktop releases from Emacspeak Inc.
  • Emacspeak-14.0 –code named TopDog–was

the first release of this millennium.

  • Emacspeak-13.0 –codenamed YellowLab– was the closing release of the 20th. century.
  • Emacspeak-12.0 –code named GoldenDog– began leveraging the evolving semantic WWW to provide task-oriented speech access to Webformation.
  • Emacspeak-11.0 –code named Aster– went the final step in making Linux a zero-cost Internet access solution for blind and visually impaired users.
  • Emacspeak-10.0 –(AKA Emacspeak-2000) code named WonderDog– continued the tradition of award-winning software releases designed to make eyes-free computing a productive and pleasurable experience.
  • Emacspeak-9.0 –(AKA Emacspeak 99) code named BlackLab– continued to innovate in the areas of speech interaction and interactive accessibility.
  • Emacspeak-8.0 –(AKA Emacspeak-98++) code named BlackDog– was a major upgrade to the speech output extension to Emacs.
  • Emacspeak-95 (code named Illinois) was released as OpenSource on the Internet in May 1995 as the first complete speech interface to UNIX workstations. The subsequent release, Emacspeak-96 (code named Egypt) made available in May 1996 provided significant enhancements to the interface. Emacspeak-97 (Tennessee) went further in providing a true audio desktop. Emacspeak-98 integrated Internetworking into all aspects of the audio desktop to provide the first fully interactive speech-enabled WebTop.

9. About Emacspeak:

Originally based at Cornell (NY) — http://www.cs.cornell.edu/home/raman —home to Auditory User Interfaces (AUI) on the WWW, Emacspeak is now maintained on GitHub —https://github.com/tvraman/emacspeak. The system is mirrored world-wide by an international network of software archives and bundled voluntarily with all major Linux distributions. On Monday, April 12, 1999, Emacspeak became part of the Smithsonian's Permanent Research Collection on Information Technology at the Smithsonian's National Museum of American History.

The Emacspeak mailing list is archived at Emacspeak Mail Archive –the home of the Emacspeak mailing list– thanks to Greg Priest-Dorman, and provides a valuable knowledge base for new users.

10. Press/Analyst Contact: Tilden Labrador

Going forward, Tilden acknowledges his exclusive monopoly on setting the direction of the Emacspeak Audio Desktop (🦮) and promises to exercise this freedom to innovate and her resulting power responsibly (as before) in the interest of all dogs.

*About This Release:


Windows-Free (WF) is a favorite battle-cry of The League Against Forced Fenestration (LAFF). –see http://www.usdoj.gov/atr/cases/f3800/msjudgex.htm for details on the ill-effects of Forced Fenestration.

CopyWrite )C( Aster, Hubbell and Tilden Labrador. All Writes Reserved. HeadDog (DM), LiveDog (DM), GoldenDog (DM), BlackDog (DM) etc., are Registered Dogmarks of Aster, Hubbell and Tilden Labrador. All other dogs belong to their respective owners.

Author: T.V Raman

Created: 2022-11-23 Wed 10:07

Validate

-1:-- Announcing Emacspeak 57.0 (Tilden) (Post T. V. Raman (noreply@blogger.com))--L0--C0--November 23, 2022 06:10 PM

Irreal: Org Tree Slide

Everybody hates slide decks. Jeff Bezos even famously banned them from Amazon. Still, most of us who are called upon to give a presentation will make slides the center of that presentation. There are, of course, dedicated programs like PowerPoint, Keynote, and the various clones that come with packages like LibreOffice but few Emacs users are going to want to wade into that swamp.

Happily there are several Emacs packages that let you prepare slides from the comfort of your editor. David Wilson over at System Crafters has an informative video that explores one of those packages: org-tree-slide.

Based on Wilson’s video, I’d judge that the application doesn’t produce slides as nice looking as some of the other packages but it does have the advantage of not needing any other packages. You just load the org-tree-slide package and you’re good to go. The input is very simple: you just make an Org file and the headers become the slides. On the plus side, you can have images and code blocks and these get exported to the slides. Wilson shows how to control things like the font and image sizes and simple animation effects.

The video is 31 minutes, 38 seconds long so you’ll need to schedule some time. If you’re looking for a simple package to generate simple slides, this package is certainly worth taking a look at.

-1:-- Org Tree Slide (Post jcs)--L0--C0--November 23, 2022 06:03 PM

Tory Anderson: viewing epub in emacs

Intro I finally arranged my employer to purchase Mastering Emacs1, which provided it in pdf and epub. PDF2 has long since been my standard thanks to being able to view it nicely on all my devices, but I thought I would give epub a try, too. It’s major feature sounds like both emacs-window text resizing, and page memory so it keeps track of where you’ve read. It turns out that the lauded epub mode has some extra steps with the installation.
-1:-- viewing epub in emacs (Post)--L0--C0--November 23, 2022 12:00 AM

Andrea: Emacs as your code-compass: who is the person who refactored most in this project?

Emacs as your code-compass: who is the person who refactored most in this project?

It is a while I don't post about code-compass. I recently jumped back in the consulting world and it is a hectic life! In a couple of months I moved from a project to another. Furthermore, I cannot say I got somebody introducing me to the software architecture of these projects (or even their status).

Lucky me these years (from Ph.D. to industry times) have given me some experience, so my boat is well equipped for this wavy sea. Also I have a great tool: in both projects I just had to rely on my Emacs for a reliable code-compass.

So armed of hotspots, knowledge and communication graphs with a bit of churn, fragmentation and complexity on the side, I could get up and running faster than ever! Yay!!

One thing I have been missing is to explore graphically who dedicated themselves to the lovely art of refactoring. Indeed, the project on which I rely, the fantastic code-maat, offers a refactoring analysis. This finds who has deleted most lines in a file using Git commits information.

Naturally deletions are an approximation for refactoring, but good enough as less code is always an improvement (at least for our eyes).

Well there I go: I added it just now. It was pretty easy because is super-similar to the knowledge graph implementation. So a tweak here and there and it is now available.

Below a video that gives you a sense of what it is about.

If you want to try that yourself it is easy: just try out code-compass ;)

Happy refactoring!

-1:-- Emacs as your code-compass: who is the person who refactored most in this project? (Post)--L0--C0--November 23, 2022 12:00 AM

Irreal: Using Icons with Mu4e

Just a quickie from Álvaro Ramírez. If you’re a Mu4e user and would like to have an email’s status shown as one or more icons instead of a series of comparatively opaque letters but don’t want to deal with all-the-icons, Ramírez has the answer for you.

It’s pretty simple. You choose the icons you want for each status indication—or simply copy Ramírez’s—and add a series of configuration items to your init.el. Those items are listed in Ramírez’s post so take a look if your interested in adding your own.

-1:-- Using Icons with Mu4e (Post jcs)--L0--C0--November 22, 2022 07:45 PM

Phil Hagelberg: in which legibility comes at a price

It's been a weird few weeks for decentralized social media. The collapse of Twitter at the hands of an incompetent billionaire has led to a massive wave of users on the Fediverse1, from under a million to over seven million now. And at the time of this writing Twitter hasn't even finished collapsing yet; the site is still hobbling along, albeit with gaping holes. Though by the time I've finished writing this post, who knows. A lot can happen.

a graph of new users per day overlaid with various events             leading to Twitter's demise; each disaster causes a spike.

As you might expect, the huge influx has caused some technical problems to the Fediverse. The mega-instances like mastodon.social saw slow page load times and hours of lag between something posted and it propagating out to other servers. More reasonably-sized servers have still seen some lesser propagation lag, but the main effect of this influx has been nontechnical. New users have had a hard time finding well-run servers that are accepting new members, and there has been a lot of complaining that the system is hard to understand or navigate due to its distributed nature.

whenever twitter makes a bunch of its users angry we get a new wave of activity on the [Fediverse] and all the new mastodon users engage in the primary hobby of a new mastodon user, which is listing all of the reasons why mastodon doesn't work. it's real fun

- @rootsworks@mastodon.social

Some of this is simply a necessary difference between a single unified corporate system to a distributed network. In the 1990s we saw a similar type of confusion as people left silos like America OnLine (AOL) and CompuServ to explore the early days of the World Wide Web. It wasn't as polished, and there was no central view of the entire network. You had to do more exploring to find independent communities that ran their own sites. People who remember making this shift know now that the effort was worth it, but back then you couldn't fault people for wondering why things couldn't just be easy like it used to be.

But I believe there's more to the situation with the Fediverse today than simply the differences that arise out of technical necessity.

I recently finished reading the book Seeing Like a State by James Scott. There's a lot to unpack in this book2, but I want to talk about the way it defines the term legibility. Legibility describes the degree to which a place is understandable and navigable to an outsider.

a street near the market in Mae Sot, Thailand

My favorite example of legibility is street addresses. When I lived in Thailand I was initially very surprised to learn that even long-time residents had a very rough grasp of the names of most of the streets in the city. People navigated by landmarks instead. As a newcomer to the city it was very disorienting; I had to set aside my ideas I brought in about how to navigate and learn to read the city like a local. In the end after living there two years I knew the names of four or five of the major streets, but when someone wanted to know where my house was, I didn't give them a street address; I told them it was a block east of the bus terminal.

This attitude towards navigating looks different depending on whether you're an outsider or a resident. To a resident it's no big deal, but to someone who's new to the city it can be frustrating and bewildering. In some cases (for instance, cities that rely on tourism) there are incentives for the locals to increase legibility, but other factors can incentivize people to reduce their legibility.

Legibility is particularly interesting when it lies at the crux of a power imbalance, and the book describes many such situations. As pre-modern states in Europe consolidated their power, they looked for ways to collect taxes and conscript soldiers more effectively. Customary naming made this very difficult.

Only wealthy aristocrats tended to have fixed surnames…Imagine the dilemma of a tithe or capitation-tax collector [in England] faced with a male population, 90% of whom bore just six Christian names (John, William, Thomas, Robert, Richard, and Henry).

Seeing Like a State by James Scott

In order to consolidate their power over their citizens, states rolled out policies to increase the legibility of the population they ruled over; they started to require that everyone take a surname in order to uniquely identify them to the state in censuses and tax documents. As you can imagine, this didn't go over well; the historical record documents intense resistance, in some cases even open rebellion. The people themselves had no need for surnames; they got along fine with a given name supplemented when necessary with contextual specifiers. "John" might be "John the Baker" in some contexts and "Short John" in others and "John Underhill" to people in the next town. This system worked fine for everyone involved, except those wishing to exert their authority from the outside.3

If this sounds familiar to you, it might be because you were paying attention to social media controversies of the last decade! Prominent advertising companies like Facebook and Google attempted to roll out tremendously unpopular policies requiring users to identify themselves using their legally-documented name4. Though these policies were always accompanied by some flimsy justification about "user safety", the real goal was to make their users more legible, primarily for advertising purposes, but also to law enforcement and other authorities.

Well, it turns out just like villagers in premodern France, lots of users don't want to make themselves more legible! Even setting aside the impossibility of a company like Facebook accurately identifying the difference between a pseudonym and a legal name, there are a lot of great reasons to not want to be easy to find. Avoiding targeted advertising is just the tip of the iceberg; ask any member of a marginalized group and they'll tell you that being easy to find can have a high cost when it exposes you to targeted abuse.

Twitter features full-text search of everything posted. This is fantastic for legibility; if you're curious about a topic, you can always see who's talking about it. One of the ways this gets used on Twitter is to pick fights. Trolls find a hot topic and barge uninvited into conversations to yell at people who disagree with their position. On the Fediverse, search is opt-in instead of opt-out. Normal text doesn't get indexed, but hashtags do. If you want your post to become searchable under certain terms, a # is all it takes, but the randos won't show up unless you go out of your way to invite them.

In some ways, people today coming to the Fediverse from corporate social media remind me of how I felt when I first moved to Thailand—lost and bewildered by the lack of street signs. They've spent a lot of time on the highways of platforms that prioritize "engagement" at all cost, and it's taking a while for it to sink in that not all the Internet works that way. They've never considered that illegibility can be a defense mechanism..

Become illegible.5


[1] The Fediverse is a network of interconnected social media servers that exchange posts. Most of its usage is based on a similar model to Twitter, but there are some systems on it that focus on photos or videos. Because the most common Fediverse server is called Mastodon, many people use the word Mastodon to talk about the network, similar to how in the 1990s people said "Internet Explorer" when they meant the web.

[2] While the book is insightful, it is pretty long, and the two case studies in the middle drag on a bit. I strongly recommend reading the first three chapters and the last two chapters, but you can still get 90% of the insight by skipping the two very detailed case studies in the middle.

[3] The scary thing about this is how absolute the normalization of surnames became over time despite the intense resistance. In the end, people accepted the greater control, and even tho surnames were rare in many societies only a few hundred years ago, nowadays they are thought of by most people as "natural".

[4] These policies often misleadingly referred to the legal name as the "real name", as if legal process had some magical access to reality itself which could not be achieved using the customary naming patterns people have been using for millennia.

[5] I have to admit to stretching this a bit for a punchy closing line, but of course it's not as simple as "legibility bad"; obviously there are many cases in which you want legibility. I'm trying to convey the fact that legibility does have downsides, and if you've never even considered this, then it's impossible for you to have a productive conversation about social software in today's context.

-1:-- in which legibility comes at a price (Post Phil Hagelberg)--L0--C0--November 22, 2022 10:16 AM

Irreal: A Conversation with Mickey

Syntopikon has an interesting interview with Mickey Petersen, the proprietor of Mastering Emacs and all around Emacs expert and expositor. He’s no stranger to Irreal readers so it’s always nice to see him discuss matters. The last time I remember seeing an interview with him was in 2014 in an on-line chat with Sacha Chua.

Like many of us, Mickey abandoned his first attempt to use Emacs. That was in his pre-college days when he was just discovering and learning Linux. Later, when he got to the university, he adopted Emacs party in reaction to the noisy voices insisting that all real hackers used Vim. When you read Mickey now, it’s easy to believe that he’s always had a thorough knowledge of Emacs and didn’t struggle like the rest of us. Of course, that’s wrong. He used it for some time before, as he says, the light came on and he realized the true potential of Emacs.

He also has an interesting exchange with the interviewer on the use of Emacs for non-technical or technical-adjacent users. The interviewer is an Emacs user too but he uses it for writing. I’ve long felt that all writers should at least try Emacs. After all, it’s all about wrangling text whether you’re a developer or a writer and Emacs excels at that. If you learn enough Elisp to make minor customization’s you can mold Emacs into a your ideal writing environment. Mickey believes that more could be done to make learning Emacs easier for the non-developer and he explores a few of those in the interview.

Like most things that Mickey’s involved with, the interview is interesting and worth reading. A few minutes of your time would be well spent.

-1:-- A Conversation with Mickey (Post jcs)--L0--C0--November 21, 2022 06:14 PM

Sacha Chua: 2022-11-21 Emacs news

Update 2022-11-21: added new packages

Links from reddit.com/r/emacs, r/orgmode, r/spacemacs, r/planetemacs, Hacker News, lobste.rs, planet.emacslife.com, YouTube, the Emacs NEWS file, Emacs Calendar, emacs-devel, and lemmy/c/emacs. Thanks to Andrés Ramírez for emacs-devel links. Do you have an Emacs-related link or announcement? Please e-mail me at sacha@sachachua.com. Thank you!

-1:-- 2022-11-21 Emacs news (Post Sacha Chua)--L0--C0--November 21, 2022 02:57 PM

Robert Enzmann: Moving My Emacs Configuration to a Literate Programming Document

I’ve got a (relatively) stable version of my Emacs configuration as a literate document now.
-1:-- Moving My Emacs Configuration to a Literate Programming Document (Post)--L0--C0--November 21, 2022 05:00 AM

Irreal: Replying to a Sender Specific Email Address

Sebastian Schulze has an interesting post on handling email To and From addresses. His procedure when supplying an Email address to, say, a Website such as some-site.com is to specify some-site.com@his-domain.com where his-domain.com is his domain. That allows him to apply appropriate filters and discover the source of spam.

In order for this to work, he needs two things:

  1. His email provider must pass all email to him regardless of the user name.
  2. He has to set the From address on any replies to some-site.com@his-domain.com.

The first item is generally doable if you have control of your domain, especially if you run your own email server. The second is a lot harder with almost every email client. Fortunately Schulze uses mu4e so it’s relatively easy with a bit of Elisp.

Actually, mu4e can almost handle this out-of-the-box. You can specify your email addresses and mu4e will respond with the appropriate From address. Schulze’s situation is a little more complicated. You could do it with vanilla mu4e but you’d have to constantly housekeep your mu4e configuration. Schulze’s solution takes care of everything automatically.

The Elisp required is minimal so it’s an easy solution providing you have your own domain and are using mu4e. My own—not as good—solution is to add specific “possibly spam” addresses to my mail server and use that for sites that are possible sources of spam. Schulze’s solution is clearly superior and worth emulating if you can.

-1:-- Replying to a Sender Specific Email Address (Post jcs)--L0--C0--November 20, 2022 07:02 PM

Noonker: Org Mode Insert Table Reference

Emacs Org-Mode tables are very powerful. The formula editor can execute elisp commands which makes for a really powerful spreadsheet editor (especially when combined with org-sbe). One big limitation I've faced is multi-line content. To solve this I've created a simple function to wrap around results of some elisp block to always return the most useful data. (org-table-create-and-insert-reference "hello") -> "hello" (org-table-create-and-insert-reference "") -> "nil" (org-table-create-and-insert-reference nil) -> "nil"
-1:-- Org Mode Insert Table Reference (Post)--L0--C0--November 20, 2022 12:00 AM
Emacs @emacs # All posts in here will have the category set to emacs
-1:--  (Post)--L0--C0--November 19, 2022 10:29 PM

Marcin Borkowski: Streamlining my workflow with Magit and BitBucket

We use BitBucket at our company, which is some source of frustration for us. One of the issues we have with BitBucket is that it seems to lack a decent CLI tool. This means that in order to e.g. create a pull request, you go to the website, click a few times and only then confirm that a PR is really what you want. Well, after some time I learned that it’s not that bad. When you git push your changes, Git (on the command line) responds with the URL you need to go to create a pull request out of the branch you just pushed. (This is most probably achieved via post-receive or some other Git hook.) Nice. Well, of course I don’t use Git from the command line – I use Magit. So naturally I wanted Emacs to extract that information for me and open the URL in the browser. It turns out that it was easier than I thought.
-1:-- Streamlining my workflow with Magit and BitBucket (Post)--L0--C0--November 19, 2022 07:55 PM

Jeremy Friesen: Project Dispatch Menu with Org Mode Metadata, Denote, and Transient

Creating a Means of Quickly Navigating Amongst a Projects Important “Pages”

At Software Services by Scientist.com I work on several different projects. Ideally, one project at a time, but within a week I might move between two or three. Note taking procedures help me re-orient to a new project.

I spent some time reflecting on the common jumping off points for a project:

Local Source Code
the local repository of code for the project; thus far each project has one repository.
Remote Source Code
the remote repository where I interact with issues and pull requests.
Remote Project Board
the page that has the current project tasks and their swimlanes.
Agenda/Timesheet
the place where I track my local time and write notes.
Local Project Note
the place where I track important links or information regarding the project.

When I’m working on the project, I’m often navigating between those five points. Since I work in Emacs I figured I’d write up some code.

First, I thought about the data. Where should I store this information? Looking at the above list, the best candidate was the Local Project Note; a note written in Org-Mode and I use Denote to help me manage this kind of note.

For each project document I added the following keywords (e.g. those that can be found by the org-collect-keywords function):

#+PROJECT_NAME:
By convention, this is the short-name that I use for my timesheet and task management. (See Org Mode Capture Templates and Time Tracking for more details.)
#+PROJECT_PATH_TO_CODE:
The file path to the code on my machine.
#+PROJECT_PATH_TO_REMOTE:
The URL of the remote repository.
#+PROJECT_PATH_TO_BOARD:
The URL of the remote project board.

An astute reader will realize that I’ve done my best to normalize the keywords. I envision that instead of a hard-coded set of “jump to” functions I could instead select the project and then iterate through the keywords keys that start with PROJECT_PATH_TO and create a selector for that. But I digress.

The Helper Functions

I wanted a common mechanism for selecting the project. I wrote the following function:

(cl-defun jf/project/list-projects (&key (project ".+")
					 (directory org-directory))
  "Return a list of `cons' that match the given PROJECT.

The `car' of the `cons' is the project (e.g. \"Take on Rules\").
The `cdr' is the fully qualified path to that projects notes file.

The DIRECTORY defaults to `org-directory' but you can specify otherwise."
  (mapcar (lambda (line)
	    (let* ((slugs (s-split ":" line))
'		   (proj (s-trim (car (cdr slugs))))
		   (filename (file-truename (s-trim (car slugs)))))
	      (cons proj filename)))
	  (split-string-and-unquote
	   (shell-command-to-string
	    (concat
	     "rg \"^#\\+PROJECT_NAME: +(" project ") *$\" " directory
	     " --only-matching --no-ignore-vcs --with-filename -r '$1' "
	     "| tr '\n' '@'"))
	   "@")))

It searches through my org-directory for the given project; by default that project is a fragment of a regular expression. That regular expression is “any and all characters.” I can use the above function as a parameter for completing-read.

I also want to set my default project. For this, I used Transient’s transient-define-suffix function. Below is jf/project/transient-current-project, a function I use to manage and display the jf/project/current-project variable.

(defvar jf/project/current-project
  nil
  "The current contextual project.")

(transient-define-suffix jf/project/transient-current-project (project)
  "Select FILES to use as source for work desk."
  :description '(lambda ()
		  (concat
		   "Current Project:"
		   (propertize
		    (format "%s" jf/project/current-project)
		    'face 'transient-argument)))
  (interactive (list (completing-read "Project: "
				      (jf/project/lis't-projects))))
  (setq jf/project/current-project project))

I also recognized that I might want to auto-magically select a project. So I wrote up the basic jf/project/find-dwim:

(defun jf/project/find-dwim ()
  "Find the current project."
  (completing-read "Project: " (jf/project/list-projects)))

The above function could look at the current clock in Org Mode and determine the associated project. Or, if I’m in a repository look to see what project it is associated with. Or whatever other mechanisms. For now, it prompts for me to pick a project.

The Interactive Functions

With the above “plumbing” I wrote five functions:

  • jf/project/jump-to-agenda
  • jf/project/jump-to-board
  • jf/project/jump-to-code
  • jf/project/jump-to-notes
  • jf/project/jump-to-remote

The jf/project/jump-to-agenda function is a bit different, it tries to jump to today’s agenda item for the project.

(cl-defun jf/project/jump-to-agenda (&optional project
				     &key
				     (tag "project")
				     (within_headline
				      (format-time-string "%Y-%m-%d %A")))
  "Jump to the agenda for the given PROJECT."
  (interactive)
  (let ((the-project (or project (jf/project/find-dwim))))
    (with-current-buffer (find-file jf/pri
mary-agenda-filename-for-machine)
      (let ((start (org-element-map (org-element-parse-buffer)
		       'headline
		     ;; Finds the begin position of:
		     ;; - a level 4 headline
		     ;; - that is tagged as a :project:
		     ;; - is titled as the given project
		     ;; - and is within the given headline
		     (lambda (hl)
		       (and (=(org-element-property :level hl) 4)
			    ;; I can't use the :title attribute as it
			    ;; is a more complicated structure; this
			    ;; gets me the raw string.
			    (string= the-project
				     (plist-get (cadr hl) :raw-value))
			    (member tag
				    (org-element-property :tags hl))
			    ;; The element must have an ancestor with
			    ;; a headline of today
			    (string= within_headline
				     (plist-get
				      ;; I want the raw title, no
				      ;; styling nor tags
				      (cadr
				       (car
					(org-element-lineage hl)))
				      :raw-value))
			    (org-element-property :begin hl)))
		     nil t)))
	(goto-char start)
	(pulsar-pulse-line)))))

The jf/project/jump-to-board function assumes a remote URL.

(cl-defun jf/project/jump-to-board (&optional
				    project
				    &key
				    (keyword "PROJECT_PATH_TO_BOARD"))
  "Jump to the given PROJECT's project board."
  (interactive)
  (let* ((the-project (or project (jf/project/find-dwim)))
	 (filename (cdar (jf/project/list-projects :project the-project))))
    (with-current-buffer (find-file-noselect filename)

      (let ((url (cadar (org-collect-keywords (list keyword)))))
	(eww-browse-with-external-browser url)))))

The jf/project/jump-to-board function assumes a directory on my local machine. The code is similar to the jf/project/jump-to-board.

(cl-defun jf/project/jump-to-code (&optional
				   project
				   &key
				   (keyword "PROJECT_PATH_TO_CODE"))
    "Jump to the given PROJECT's source code."
    (interactive)
    (let* ((the-project (or project (jf/project/find-dwim)))
           (filename (cdar (jf/project/list-projects :project the-project))))
      (with-current-buffer (find-file-noselect filename)
        (let ((filename (file-truename (cadar
					(org-collect-keywords
					 (list keyword))))))
          (if (f-dir-p filename)
              (dired filename)
            (find-file filename))))))

The jf/project/jump-to-notes prompts for the project and then finds the filename.

(cl-defun jf/project/jump-to-notes (&optional project)
  "Jump to the given PROJECT's notes file.

Determine the PROJECT by querying `jf/project/list-projects'."
  (interactive)
  (let* ((the-project (or project (jf/project/find-dwim)))
	 (filename (cdar (jf/project/list-projects :project the-project))))
    (find-file filename)))

Akin to the jf/project/jump-to-board, the jf/project/jump-to-remote opens a remote URL.

(cl-defun jf/project/jump-to-remote (&optional
				     project
				     &key
				     (keyword "PROJECT_PATH_TO_REMOTE"))
  "Jump to the given PROJECT's remote."
  (interactive)
  (let* ((the-project (or project (jf/project/find-dwim)))
	 (filename (cdar (jf/project/list-projects :project the-project))))
    (with-current-buffer (find-file-noselect filename)
      (let ((url (cadar (org-collect-keywords (list keyword)))))
	(eww-browse-with-external-browser url)))))

The Menu

Using Transient I define a menu for my projects. Lower case is for dispatching to the current project. Upper case prompts for the project then dispatches.

(transient-define-prefix jf/project/menu ()
  "My Project menu."
  ["Projects"
   ["Current project"
    ("a" "Agenda…" (lambda () (interactive)
		     (jf/project/jump-to-agenda jf/project/current-project)))
    ("b" "Board…" (lambda () (interactive)
		    (jf/project/jump-to-board jf/project/current-project)))
    ("c" "Code…" (lambda () (interactive)
		   (jf/project/jump-to-code jf/project/current-project)))
    ("n" "Notes…" (lambda () (interactive)
		    (jf/project/jump-to-notes jf/project/current-project)))
    ("r" "Remote…" (lambda () (interactive)
		     (jf/project/jump-to-remote jf/project/current-project)))
    ("." jf/project/transient-current-project :transient t)]
 '  ["Other projects"
    ("A" "Agenda…" jf/project/jump-to-agenda)
    ("B" "Board…" jf/project/jump-to-board)
    ("C" "Code…" jf/project/jump-to-code)
    ("N" "Notes…" jf/project/jump-to-notes)
    ("R" "Notes…" jf/project/jump-to-remote)]
   ])

Conclusion

During my day I spend a lot of time writing and reading; and for large chunks of time those are all related to a single project. Each project has predictable “places” where I will read and write.

The above functions help me both document the relationship of those predictable “places” and automate my navigation to those different tools. In all things Emacs remains my homebase; it is where I can go to re-orient.

My jf-project.el document has the above code and any further updates, bug fixes, etc to the above now static code.

-1:-- Project Dispatch Menu with Org Mode Metadata, Denote, and Transient (Post Jeremy Friesen (jeremy@takeonrules.com))--L0--C0--November 19, 2022 01:03 PM

Robert Enzmann: Virtual Environments with Eglot, Tramp, and Pyright

Motivation # My most reliable setup for developing Python projects on remote hosts with LSP support so far has been with eglot and pyright.
-1:-- Virtual Environments with Eglot, Tramp, and Pyright (Post)--L0--C0--November 19, 2022 05:00 AM

Sacha Chua: Solving the mastodon.el error mastodon-auth--access-token: invalid

If you get mastodon-auth--handle-token-response: Mastodon-auth--access-token: invalid_grant: The provided authorization grant is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client. while trying to set up mastodon.el from MELPA, you might have an outdated version. Try the following steps:

  • M-x package-delete mastodon
  • Restart Emacs
  • M-x package-refresh-contents
  • M-x package-install mastodon

If that doesn't work, try installing it from the Git repository: https://codeberg.org/martianh/mastodon.el.git

Posting this here to make it searchable.

-1:-- Solving the mastodon.el error mastodon-auth--access-token: invalid (Post Sacha Chua)--L0--C0--November 18, 2022 04:48 PM

Irreal: A New Take On Quitting Vim

Finally! A new take on the quitting Vim meme:

That’s actually pretty funny. Of course, as someone pointed out it could just as well apply to Emacs. Since this isn’t Friday, I won’t toss in red meat by noting that the real problem is that Emacs and Vim don’t have a menu item with a Quit entry1 for the cognitively challenged.

Footnotes:

1

Yes, yes. I know. This is a humor piece. Humor me.

-1:-- A New Take On Quitting Vim (Post jcs)--L0--C0--November 17, 2022 05:43 PM

TAONAW - Emacs: Writing Modes

After working on my wiki for a couple of weeks straight, I’m starting to calm down a bit. I’m thinking of what I write, and where.

Since the wiki is organized by categories, it’s easy to start topics without committing to a whole body of text. Say I want to write about a video game I just finished. I could create a “Video Games” topic and under it, another article: “Doom.” “Video Games” remain blank, a placeholder until a point in the future when I have more to expand on.

While this is doable on most blogs (this one included), the idea of going back to a post feels a bit out of place, since the blogs are chronological.

On the other hand, writing in the blog is more personal. It’s org-mode, which I also use to write my journal. Emacs just feels personal. It’s a superior writing environment that lets me spill my thought on the screen without getting distracted. Writing in a blog just feels more like a narrative unfolding, more of the why and not just the how. It’s not a coincidence this blog is called what it’s called; I always reserved a sense of irony in what I write.

Writing has become a part of my identity. I spend hours in front of Emacs each day writing what I do and organizing my day. By extension, having a blog lets me extend this identity further: I am more me because I blog.

Just thought I’d share.

-1:-- Writing Modes (Post)--L0--C0--November 17, 2022 12:05 PM

Kisaragi Hiu: Making a serverless SvelteKit site that reads data from a local SQLite database

Rough draft. I might later provide a minimum template for reference. We're not reading and writing runtime data. A dedicated database (like Supabase) is better in that case. Here, I just want to read from an already created SQLite database. “Serverless” here means “the server side code is written as short-lived one-request functions”, which in practice means “I'm using Netlify (or Vercel or Cliudflare etc.) to make the site with no upfront monetary investment and no need to manage my own server”, which is its nornal definition despite contradicting what “server-less” may seem to suggest.
-1:-- Making a serverless SvelteKit site that reads data from a local SQLite database (Post Kisaragi Hiu)--L0--C0--November 17, 2022 11:46 AM

200ok: reClojure 2022, now with a physical venue in Lucerne!

reClojure is a free, community driven conference that brings together inspiring speakers in a warm and friendly atmosphere. This year, it's a two-day (Dec 2 and 3) conference.

We are also happy to announce that this year we will have a physical venue in Switzerland where we can gather as a community, watch talks, hack all things Clojure, and have a good time together.

Our hosts will be Ardeo (ardeo.ch) - the venue is their Coworking Hub in Lucerne. The space is just a couple minutes from Lucerne central station and features three rooms - one per track and a hacking/chillout space. Attending the conference is free (as in beer). Optional donations are welcome. For Ardeo, the Coworking Hub is central to the sharing economy and practising openness and transparency. As a driver for innovation, Ardeo is a long-standing partner of 200ok. Phil and Alain from 200ok are co-hosting.

The first day, Dec 2nd, will be hosted in its entirety from 10:30 until 21:30. The second day is in conflict with the EmacsConf 2022, which is also being hosted in the space on the Dec 3rd, so the official duration for the reClojure event will be scheduled as 10:30 - 14:30. After that the focus will be on the EmacsConf. Optionally, should there be demand and space we might run the rest of the reClojure talks in a separate room.

You can find details about the reClojure schedule on their website https://www.reclojure.org/

Ardeos' Coworking Hub spots for reClojure 2022 are limited to 25. Hence, sign up early, and release your seat just as early if you cannot attend. For signing up, please use this Meetup event:

Please make sure to sign up directly at the Meetup event of the organizers, as well, so that they have a proper grasp of how many people attend the online conference: https://www.meetup.com/london-clojurians/events/289598000/

We are very much looking forward to reClojure 2022 - to meeting great people, having interesting discussions and sharing all things Clojure and Lisp \(^_^)/


If you'd like to attend reClojure and EmacsConf, please sign up for both events separately. Here's more information about EmacsConf.


Some impressions from Ardeos Coworking Hub in Lucerne

-1:-- reClojure 2022, now with a physical venue in Lucerne! (Post Alain M. Lafon, Alex Mihov, Phil Hofmann (alain@200ok.ch))--L0--C0--November 17, 2022 01:00 AM

Irreal: Mike Zamansky Is Retiring

Mike Zamansky, who is well known to Irreal readers for his excellent, some say definitive, Using Emacs Series just announced that he is planning on retiring at the end of the Spring semester. In a series of three posts Zamansky lays out why he is retiring, what he feels he’s accomplished, and what his future might hold.

Irreal has focused almost exclusively on his Using Emacs Videos but I read all his posts and several of them are interesting even if not Irreal fodder. If you’re interested in CS education and how best to train new engineers, you should definitely be reading his blog. It’s low traffic so it’s easy to keep up with.

From a purely selfish point of view I hope he devotes all his newly found free time to making new Emacs videos but realistically we’ll be lucky and happy to get one every now and then. Whatever future he decides on, Irreal wishes him the best and is happy to recognize his many contributions to Emacs and CS education.

-1:-- Mike Zamansky Is Retiring (Post jcs)--L0--C0--November 16, 2022 07:14 PM

Jean-Christophe Helary: An even newer version of my Capture app

This is a newer version of what I wrote on Sunday.

I figured a number of things.

  • I’m not going to call this app at random, so I could just as well action something in Emacs when I dismiss the dialog.
  • My default does not have to be selected. If it is not selected, I can use the fact that nothing is selected as the default.

So, I decided that dismissing the script would bring Emacs to the front, so that I can just write something without anything captured.

Also, I added an option to display the Capture interactive selector in Emacs, in case I want to capture something that’s not in the list (i.e., something that I would not capture that often).

I also put handlers, to kind of prettify the code.



The next step, as written in the script, is to combine that code with the “Open with Emacs” code that I have and check whether Finder is front, in which case I either open the selection or the enclosing folder.

I’ll try to not scratch that itch before I’m done with urgent work. . .


####################################


use AppleScript version "2.4" -- Yosemite (10.10) or later

use scripting additions

use framework "Foundation"


#########

# First, I'll be using the Foundation framework because otherwise it 

# would be non-trivial to find "the index of a given item in my list". 

# And for that I'll just need to use NSArrays. I did not figure that out 

# by myself, I found the hint on stackoverflow.

# reference: https://stackoverflow.com/a/65690139/5511978

#########


property NSArray : class "NSArray"


#########

# Then, I'm setting my paths to Emacs and emacsclient.

#########


set myEmacs to "/.../Emacs.app"

set myEmacsclient to "/.../Emacs.app/Contents/MacOS/bin/emacsclient"


#########

# Here, I create the list of template items I want to quickly access. I 

# have many more, but the others are more about long-form writing, so I 

# figured I'd be facing Emacs when I need to access them.

# This list is basically "capture", "todo", "done", "dictionary", "notes" and "drafts".

# Then I transform that into a Foundation array

#

# "capture" allows me to display the interactive template chooser.

#########


set myList to {"capture", "à faire", "fait", "dictionnaire", "notes", "brouillon"}

set myArray to NSArray's arrayWithArray:myList


#########

# Here are the template keys that I use in my Emacs interactive capture 

# template.

# Their order corresponds to the order of the above list items.

#########


set myKeys to {"c", "a", "f", "d", "n", "b"}


#########

# Now comes the interactive item selection window. That's the thing 

# that's apparently called when I call the app. All the rest takes place 

# behind the scenes.

# I can just hit Enter without selecting anything.

# I'll use that to call the default template, which is "fait".

#

# I can hit the first letter of any item for it to be selected, then I 

# hit Enter to simulate clicking on OK.

# The "capture" (c) key is special since it allows me to display the 

# Emacs interactive template selection dialog.

# I can dismiss the dialog with either hitting Escape or clicking on 

# Cancel. But since I'm not calling the dialog by mistake, I use that 

# action to just bring Emacs to the front.

#

# I'll probably use that in a future version to call Emacs on selected 

# file and folders to open them or open dired.

#

# Then I'll need to move all that into a macOS service that I call with 

# a simple shortcut so that I don't have to:

# - call Spotlight (Cmd+Space)

# - call the app (>C)

#########


try

set captureChoice to (choose from list myList with title "Emacs" with prompt "Défaut = \"fait\"" with empty selection allowed)

set captureChoice to item 1 of captureChoice

on error

if captureChoice is false then

myEmacsComesForward()

return

end if

if length of captureChoice is 0 then

set captureChoice to "fait"

end if

end try


#########

# Here comes the place where I need Foundation's arrays.

# Basically, the line says "You just selected something, find its index in the 

# list where it belongs, and get me the letter that has the same index 

# in the myKeys list."

#

# I'm adding a few parameters to see whether I'll use the contents of 

# the clipboard or not, and if I want to automatically send the template 

# key or let Emacs propose me the interactive selection dialog.

#########


set myTemplateKey to item ((myArray's indexOfObject:captureChoice) + 1) of myKeys



if myTemplateKey is in {"d", "n"} then

set useBody to true

else

set useBody to false

end if


if myTemplateKey is in {"c"} then

set interactiveCapture to true

else

set interactiveCapture to false

end if


#########

# For 2 items, "dictionnaire" and "notes", I'm thinking that I'll 

# probably have found something in a document that I'm reading, I'll need

# to copy it for use later on in the capture buffer.

# In the case of "dictionary", it's a word that I want to check, and I'll 

# use that as the title of the captured item.

# In the case of "notes", it's probably a sentence, or a paragraph that 

# I want to keep in the body of a captured item.

# I won't use the selection for the other items.

# For that, I'll put the selection (the clipboard) into the &body part of

# the org-protocol command.

#########


if useBody is true then

set myTemplateBody to "&body=" & (the clipboard)

else if useBody is false then

set myTemplateBody to ""

end if


#########

# The &body part, though, is not super clearly explained in the 

# org-mode manual:

#

# %i              The selected text

#

# Basically, the value of &body is the contents of %i in the capture template.

# I don't know why the manual mentions "the selected text" since you can put

# whatever you want in &body.

#

# In my templates, I've used it this way:

#

# ("n" "choses à noter

# notes | à lire | code | inspiration" entry (file "~/org/memo.org")

# "* [%u]  %?\n%i" :empty-lines 0 :unnarrowed nil)

#

# Here, %i, the contents of the clipboard, will be inserted in the body 

# of the capture buffer, under the headline (notice the "\n"). And the cursor

#  (%?) is waiting for me inside the headline.

#

# or:

#

# ("d" "Dictionnaire" entry (file+datetree "/Users/suzume/org/dico.org")

# "* [%<%H:%M>] %i\n%?" :empty-lines 0 :unnarrowed nil)

#

# where %i will be inside the headline and the body of the capture 

# (supposedly the term definition) will come after the line-break, where

# the cursor is waiting for my input (%?).

#########



#########

# Et voilà !

# The org-protocol command can be built, and sent to emacsclient:

#########


if interactiveCapture is true then

set myCaptureCommand to myEmacsclient & " -e \"(org-capture)\" -n"

else if interactiveCapture is false then

set myCaptureCommand to myEmacsclient & " \"org-protocol://capture?template=" & myTemplateKey & myTemplateBody & "\""

end if



#########

# Here, I make sure that Emacs is in front of me.

# If Emacs is not launched, it is now launched, which is important, 

# because my setting also starts emacs-server, without which I could not 

# use emacsclient.

#########


myEmacsComesForward()


#########

# And last but not least, the org-protocol command is sent to the 

# shell, and with Emacs at the front with the cursor waiting for me,

# I can start working right away in my capture buffer.

#########


myEmacsDoesSomething(myCaptureCommand)


#############################################


on myEmacsComesForward()

try

tell application "System Events" to tell process "Emacs" to set frontmost to true

on error

tell application myEmacs

activate

end tell

end try

end myEmacsComesForward


on myEmacsDoesSomething(myCaptureCommand)

try

do shell script myCaptureCommand

on error

log "Emacs au premier plan"

end try

end myEmacsDoesSomething


-1:-- An even newer version of my Capture app (Post suzume (noreply@blogger.com))--L0--C0--November 16, 2022 06:15 AM

Irreal: Solving Problems With Some Quick Elisp

I often read complaints about how hard it is to learn Elisp and that therefore we should rewrite Emacs in Javascript or something equally silly. The fact is, of course, that Elisp, like most Lisps, is actually easy to learn and once you’ve spend a bit of time with it, you’ve got a very powerful tool for solving text manipulation problems or, really, just about any problem at all.

Marcin Borkowski (mbork) has a short post that illustrates this nicely. Mbork’s problem is a simple one. He needs to replace all backslashes with double backslashes. That’s a trivial problem in Emacs but Mbork wants to replace only single backslashes so the obvious solutions like replace-regexp don’t quite do the job. No matter, he simply wrote a bit of Elisp that, he says, took him about 6 minutes including the inevitable debugging.

Folks are fond of pointing out, correctly, that Elisp is not the best Lisp but it’s more than good enough for its domain. Sure, things like name spaces would be nice but look at this way, part of what make Elisp so easy to learn is its simplicity.

-1:-- Solving Problems With Some Quick Elisp (Post jcs)--L0--C0--November 15, 2022 07:57 PM

Sacha Chua: Logging sent messages to Org Mode with message-sent-hook

I wanted to e-mail all the EmacsConf speakers who had already uploaded their videos, and I wanted to keep track of the fact that I'd mailed them by adding a note to the :LOGBOOK: drawer in their talk heading. That way, organizers can just look at the logbook to see if we've mailed someone instead of digging through our mailboxes.

org-store-log-note assumes that it's called from the log buffer created by org-add-log-note. It doesn't seem to have a smaller function that can be called to store notes non-interactively, but that's okay. We can just set up the correct markers and call it from a temporary buffer.

(defun emacsconf-add-to-logbook (note)
  "Add NOTE as a logbook entry for the current subtree."
  (move-marker org-log-note-return-to (point))
  (move-marker org-log-note-marker (point))
  (with-temp-buffer
    (insert note)
    (let ((org-log-note-purpose 'note))
      (org-store-log-note))))

Then it's convenient to have a function that adds a note to a specified talk:

(defun emacsconf-add-to-talk-logbook (talk note)
  "Add NOTE as a logbook entry for TALK."
  (interactive (list (emacsconf-complete-talk) (read-string "Note: ")))
  (save-excursion
    (emacsconf-with-talk-heading talk
      (emacsconf-add-to-logbook note))))

I discard many drafts on the way to finalizing the process, so I want the note to be stored only after I actually send the mail. That's the job of message-sent-hook. My mail merge function calls compose-mail, sets up the body of the buffer, and then adds a lambda function to message-sent-hook to file the note in the logbook when sent.

(add-hook 'message-sent-hook
          `(lambda ()
             (mapc
              (lambda (o)
                (emacsconf-add-to-talk-logbook o "Sent speaker-after-video email"))
              (list ,@(mapcar (lambda (talk) (plist-get talk :slug)) talks))))
          nil t)

To see the mail merge code in context, you can check out the TODO entry at https://emacsconf.org/2022/organizers-notebook/#speaker-after-video . It uses functions from emacsconf.el and emacsconf-mail.el at https://git.emacsconf.org/emacsconf-el/ .

-1:-- Logging sent messages to Org Mode with message-sent-hook (Post Sacha Chua)--L0--C0--November 15, 2022 01:46 AM

Andrea: Catch you JS console.log you forgot to remove with Emacs and Magit

-1:-- Catch you JS console.log you forgot to remove with Emacs and Magit (Post)--L0--C0--November 15, 2022 12:00 AM

Marcin Borkowski: Doubling backslashes

Today’s post is not meant to be very useful to most people, but it serves as a demonstration of a point (well, that, and a bit of advertisement;-)). However strange it may sound, a few days ago I have a very atypical need. I needed to move some LaTeX code to a JSON file. This meant that all the backslashes had to be doubled, of course – LaTeX code is full of them, and they need to be escaped in JSON. Obviously, query-replace​’ing backslashes with double backslashes is easy, and query-replace only operates on the region when it is active, but I wanted to make sure I didn’t replace them twice by accidentally marking too much. So – partly as an exercise, I guess – I decided to write a command to replace every backslash in the region by two backslashes, but only if it was a single one.
-1:-- Doubling backslashes (Post)--L0--C0--November 14, 2022 08:43 PM

Irreal: Killing Processes From Within Emacs

Okay, okay: I’m weak and can’t stick to even the promises I make to myself. This is yet another post on Álvaro Ramírez’s dwim-shell-command framework. Yesterday, it was combining JPEGs into a single PDF file; today it’s killing processes from within Emacs.

I really like Ramírez’s solution but not for the reason you might think. It’s nice to be able to kill a process from within Emacs but I have almost no need to that. The reason is that I spend virtually all my time in Emacs so if any process needs to be killed, it’s usually going to be Emacs. The second reason is that when I do need to kill a process, I simply click on the Apple icon and choose Force Quit from the menu. That does require the mouse but it’s quick and easy and, most importantly, works even when Emacs is the application needing killing. Still, Ramírez’s, and your, workflow is likely different from mine so it’s easy to see how this can be a good solution.

Why do I like it, then? It’s that it’s a beautiful piece of code and shows how Elisp is well up to the task of retrieving and acting on system information that we usually think of as requiring low level system programming to get at. It’s all Lisp; no cheating by dropping into C or shelling out to a system utility. It’s very nice and well worth a few minutes of study.

-1:-- Killing Processes From Within Emacs (Post jcs)--L0--C0--November 14, 2022 04:20 PM

Sacha Chua: 2022-11-14 Emacs news

Links from reddit.com/r/emacs, r/orgmode, r/spacemacs, r/planetemacs, Hacker News, lobste.rs, planet.emacslife.com, YouTube, the Emacs NEWS file, Emacs Calendar, emacs-devel, and lemmy/c/emacs. Thanks to Andrés Ramírez for emacs-devel links. Do you have an Emacs-related link or announcement? Please e-mail me at sacha@sachachua.com. Thank you!

-1:-- 2022-11-14 Emacs news (Post Sacha Chua)--L0--C0--November 14, 2022 02:28 PM

Sacha Chua: On Mastodon: @sachac@emacs.ch

Now that the kiddo's reasonably well-settled into virtual school and EmacsConf is chugging along nicely, I finally have a little time to explore Mastodon, a federated social network that quite a lot of people have been shifting to (and quite a lot of people have been on all along). When @louis@emacs.ch e-mailed me about including the new emacs.ch Mastodon instance in Emacs News, I figured I'd set up a profile for myself and have a look around.

I like to keep an eye on posts mentioning Emacs once in a while, which might be a little more complicated than it is on Twitter given the distributed nature of Mastodon. Anyway, if you post something you'd like me to include in Emacs News, please mention me at @sachac@emacs.ch. Thanks!

I've also set up a bot that posts things from planet.emacslife.com. It's at https://emacs.ch/@emacslife .

I tend to scroll through Mastodon on my phone or using mastodon.el, which is really nice for keyboard navigation.

Update 2022-11-14: I think I've set it up so that @sacha@sachachua.com resolves to my profile at emacs.ch, so you can use either @sacha@sachachua.com or @sachac@emacs.ch. Useful: https://blog.maartenballiauw.be/post/2022/11/05/mastodon-own-donain-without-hosting-server.html and https://willnorris.com/2014/07/webfinger-with-static-files-nginx/ (thanks, @maartenballiauw@mastodon.online !)

See y'all there!

-1:-- On Mastodon: @sachac@emacs.ch (Post Sacha Chua)--L0--C0--November 13, 2022 10:16 PM

Irreal: Combining Jpegs

I keep promising myself that I’m not going to publish anymore posts about Álvaro Ramírez’s dwim-shell-command articles but he keeps finding compelling new applications for it. The latest is a problem I often have: combining several JPEG images into a single PDF. For me, this usually comes up when I want to combine several receipt images—a bill and credit card receipt, for example—into a single PDF for tax purposes. That comes up all the time in my workflow and Ramírez’s simple application makes it easy.

Ramírez’s post is a useful one if you aren’t aware of the dwim-shell-command framework because he lists all the applications that he’s made/discovered for the it. If, like me, you like to stay within Emacs but sometimes (or often) need to run some application from the command line, dwim-shell-command is just what you need. That’s especially true if the command has a complicated, hard to remember syntax. You encapsulate all the complexity in a simple Emacs function and invoke it from within Emacs. What could be better?

-1:-- Combining Jpegs (Post jcs)--L0--C0--November 13, 2022 05:11 PM

Jean-Christophe Helary: New Capture app, with org-protocol this time.

Just about 5 years ago, I wrote a Capture (really) everywhere article where I described a simple AppleScript application that could be launched from Spotlight and that would call org-capture in a running instance of Emacs.

I had a really nice time with that app, until sandboxing became stricter, and it became difficult to reliably control applications with keystrokes sent from System Events.

I eventually rewrote the application, and it basically became a simple call to emacsclient:


set myCaptureCommand to myEmacsclient & " -e \"(org-capture)\" -n"

do shell script myCaptureCommand


Here again, the app worked well, and I could enjoy spending time crafting org-capture templates, like everyone else does when not capturing things.

Then, it occurred to me that instead of

  • calling Spotlight,
  • calling >Capture.app,
  • hitting the template key in Emacs,
  • capture my things,

I could create specialized little apps that would call a given template that I often use. Like the "fait" (done) template that I use a number of times during the day to write down what I've accomplished so far.


I started investigating in that direction, trying to use various org-capture options, but I could not make it work. Then I found a number of interesting articles that helped me figure out my new solution: 

When I read that I could use the org-protocol to set the template key, I immediately thought that I could implement a little interactive template selector in AppleScript that would automatically put me in the right capture buffer.

And that's what I've been doing today, and I'll properly document that in my daily log, with that application, when I'm done with this article...


So, first, here is the app. It's just out of the oven, it works, I've not tested it extensively, so there might be glitches here and there, but it looks OK.

The main difference is that I'm using emacsclient to work with org-protocol here, instead of having it evaluate a call to (org-capture).

When I call it, it displays the following list item selector:

If I have copied something from a document on my machine, the copied contents will be used in the headline for "dictionnaire":

Here, I had copied "統一教会" from an article I was reading, to gather notes about the organisation.

And the copied contents will be used in the body of the capture buffer if I selected "notes":

Here, it is a short article about 伊藤詩織 and her recent win in court. Now I just have to put a title and eventually write more about the item.


As usual, the explanations come as comments in the AppleScript code so that you can just copy-paste the thing and test it. Although in this case, there are many things that depend on my setup that I doubt it would work out of the box.

####################################

use AppleScript version "2.4" -- Yosemite (10.10) or later

use scripting additions

use framework "Foundation"


#########

# First, I'll be using the Foundation framework because otherwise it 

# would be non-trivial to find "the index of a given item in my list". 

# And for that I'll just need to use NSArrays. I did not figure that out 

# by myself, I found the hint on stackoverflow.

# reference: https://stackoverflow.com/a/65690139/5511978

#########


property NSArray : class "NSArray"


#########

# Then, I'm setting my paths to Emacs and emacsclient.

# Change the values to something that works for you.

#########


set myEmacs to "/path/to/Emacs.app"

set myEmacsclient to "/path/Emacs.app/Contents/MacOS/bin/emacsclient"



#########

# Here, I create the list of template items I want to quickly access. I 

# have many more, but the others are more about long-form writing, so I 

# figured I'd be facing Emacs when I need to access them.

# This list is basically "todo", "done", "dictionary", "notes" and "drafts".

# Then I transform that into a Foundation array

#########


set myList to {"à faire", "fait", "dictionnaire", "notes", "brouillon"}

set myArray to NSArray's arrayWithArray:myList



#########

# Here are the template keys that I use in my Emacs interactive capture 

# template.

# Their order corresponds to the order of the above list items.

#########


set myKeys to {"a", "f", "d", "n", "b"}



#########

# Now comes the interactive item selection window. That's the thing 

# that's apparently called when I call the app. All the rest takes place 

# behind the scenes.

#

# That's the thing that you see above in the first screenshot.

# I can hit the first letter of any item for it to be selected, then I 

# hit Enter to simulate clicking on OK.

#########


set captureChoice to item 1 of (choose from list myList with title "Capture" default items "fait" with prompt "Choix")



#########

# Here comes the place where I need Foundation's arrays.

# Basically, the line says "You just selected something, find its index in the 

# list where it belongs, and get me the letter that has the same index 

# in the myKeys list."

#########


set myTemplateKey to item ((myArray's indexOfObject:captureChoice) + 1) of myKeys



#########

# For 2 items, "dictionnaire" and "notes", I'm thinking that I'll 

# probably have found something in a document that I'm reading, I'll need

# to copy it for use later on in the capture buffer.

# In the case of "dictionary", it's a word that I want to check, and I'll 

# use that as the title of the captured item.

# In the case of "notes", it's probably a sentence, or a paragraph that 

# I want to keep in the body of a captured item.

# 

# I won't use the selection for the other items.

# For that, I'll put the selection (the clipboard) into the &body part of

# the org-protocol command.

#########


set myTemplateBody to ""


if myTemplateKey is in {"d", "n"} then

set myTemplateBody to "&body=" & (the clipboard)

end if


#########

# The &body part, though, is not super clearly explained in the 

# org-mode manual:

#

%i              The selected text

#

# Basically, the value of &body is the contents of %i in the capture template.

# I don't know why the manual mentions "the selected text" since you can put

# whatever you want in &body.

#

# In my templates, I've used it this way:

#

# ("n" "choses à noter

#  notes | à lire | code | inspiration" entry (file "~/org/memo.org")

# "* [%u]  %?\n%i" :empty-lines 0 :unnarrowed nil)

#

# Here, %i, the contents of the clipboard, will be inserted in the body 

# of the capture buffer, under the headline (notice the "\n"). And the cursor

#  (%?) is waiting for me inside the headline.

#

# or:

#

# ("d" "Dictionnaire" entry (file+datetree "/Users/suzume/org/dico.org")

# "* [%<%H:%M>] %i\n%?" :empty-lines 0 :unnarrowed nil)

#

# where %i will be inside the headline and the body of the capture 

# (supposedly the term definition) will come after the line-break, where

# the cursor is waiting for my input (%?).

#########



#########

# Et voilà !

# The org-protocol command can be built, and sent to emacsclient:

#########


set myOrgProtocolCommand to myEmacsclient & " \"org-protocol://capture?template=" & myTemplateKey & myTemplateBody & "\""



#########

# Here, I make sure that Emacs is in front of me.

# If Emacs is not launched yet, it is now launched, which is important, 

# because my setting also starts emacs-server, without which I could not 

# use emacsclient.

#########


try

tell application "System Events" to tell process "Emacs" to set frontmost to true

on error

tell application myEmacs

activate

end tell

end try



#########

# And last but not least, the org-protocol command is sent to the 

# shell, and with Emacs at the front with the cursor waiting for me,

# I can start working right away in my capture buffer.

#########


try

do shell script myOrgProtocolCommand

on error

display alert "ooops"

end try


#############################################

-1:-- New Capture app, with org-protocol this time. (Post suzume (noreply@blogger.com))--L0--C0--November 13, 2022 09:44 AM

Alvaro Ramirez: Emacs: quickly killing processes

12 November 2022 Emacs: quickly killing processes

Every so often, I need to kill the odd unresponsive process. While I really like proced (check out Mickey Petersen's article), I somehow find myself using macOS's Activity Monitor to this purpose. Kinda odd, considering I prefer to do these kinds of things from Emacs.

What I'd really like is a way to quickly fuzzy search a list of active processes and choose the unresponsive culprid, using my preferred completion frontend (in my case ivy).

kill_x1.8.webp

The function below gives us a fuzzy-searchable process utility. While we could use ivy-read directly in our implementation, we're better of using completing-read to remain compatible with other completion frameworks. I'm a big fan of the humble completing-read. You feed it a list of candidates and it prompts users to pick one.

To build our process list, we can lean on proced's own source: proced-process-attributes. We transform its output to an alist, formatting the visible keys to contain the process id, owner, command name, and the command line which invoked the process. Once a process is chosen, we can send a kill signal using signal-process dwim-shell-command and our job is done.

(require ' dwim-shell-command)
(require ' map)
(require ' proced)
(require ' seq)

(defun  dwim-shell-commands-kill-process ()
   "Select and kill process."
  (interactive)
  (let* ((pid-width 5)
         (comm-width 25)
         (user-width 10)
         (processes (proced-process-attributes))
         (candidates
          (mapcar (lambda (attributes)
                    (let* ((process (cdr attributes))
                           (pid (format (format  "%%%ds" pid-width) (map-elt process 'pid)))
                           (user (format (format  "%%-%ds" user-width)
                                         (truncate-string-to-width
                                          (map-elt process 'user) user-width nil nil t)))
                           (comm (format (format  "%%-%ds" comm-width)
                                         (truncate-string-to-width
                                          (map-elt process 'comm) comm-width nil nil t)))
                           (args-width (- (window-width) (+ pid-width user-width comm-width 3)))
                           (args (map-elt process 'args)))
                      (cons (if args
                                (format  "%s %s %s %s" pid user comm (truncate-string-to-width args args-width nil nil t))
                              (format  "%s %s %s" pid user comm))
                            process)))
                  processes))
         (selection (map-elt candidates
                             (completing-read  "kill process: "
                                              (seq-sort
                                               (lambda (p1 p2)
                                                 (string-lessp (nth 2 (split-string (string-trim (car p1))))
                                                               (nth 2 (split-string (string-trim (car p2))))))
                                               candidates)  nil t)))
         (prompt-title (format  "%s %s %s"
                               (map-elt selection 'pid)
                               (map-elt selection 'user)
                               (map-elt selection 'comm))))
    (when (y-or-n-p (format  "Kill? %s" prompt-title))
      (dwim-shell-command-on-marked-files
       (format  "Kill %s" prompt-title)
       (format  "kill -9 %d" (map-elt selection 'pid))
        :utils  "kill"
        :error-autofocus t
        :silent-success t))))

I've pushed dwim-shell-commands-kill-process to my config dwim-shell-commands.el. Got suggestions? Alternatives? Lemme know.

Update

I've moved dwim-shell-commands-kill-process from my Emacs config to dwim-shell-commands.el. A few advantages:

  • Killing processes is now async.
  • Should anything go wrong, an error message is now accessible.
  • You can easily install via MELPA.

If you prefer the previous version (without a dependency on dwim-shell-command), have a look at the initial commit.

-1:-- Emacs: quickly killing processes (Post)--L0--C0--November 13, 2022 12:55 AM