Latest Posts (20 found)
xenodium 4 days ago

agent-shell 0.17 improvements + MELPA

While it's only been a few weeks since the last agent-shell post , there are plenty of new updates to share. What's agent-shell again? A native Emacs shell to interact with any LLM agent powered by ACP ( Agent Client Protocol ). Before getting to the latest and greatest, I'd like to say thank you to new and existing sponsors backing my projects. While the work going in remains largely unsustainable, your contributions are indeed helping me get closer to sustainability. Thank you! If you benefit from my content and projects, please consider sponsoring to make the work sustainable. Work paying for your LLM tokens and other tools? Why not get your employer to sponsor agent-shell also? Now on to the very first update… Both agent-shell and acp.el are now available on MELPA. As such, installation now boils down to: OpenCode and Qwen Code are two of the latest agents to join agent-shell . Both accessible via and through the agent picker, but also directly from and . Adding files as context has seen quite a few improvements in different shapes. Thank you Ian Davidson for contributing embedded context support. Invoke to take a screenshot and automatically send it over to . A little side-note, did you notice the activity indicator in the header bar? Yep. That's new too. While file completion remains experimental, you can enable via: From any file you can now invoke to send the current file to . If region is selected, region information is sent also. Fancy sending a different file other than current one? Invoke with , or just use . , also operates on files (selection or region), DWIM style ;-) You may have noticed paths in section titles are no longer displayed as absolute paths. We're shortening those relative to project roots. While you can invoke with prefix to create new shells, is now available (and more discoverable than ). Cancelling prompt sessions (via ) is much more reliable now. If you experienced a shell getting stuck after cancelling a session, that's because we were missing part of the protocol implementation. This is now implemented. Use the new to automatically insert shell (ie. bash) command output. Initial work for automatically saving markdown transcripts is now in place. We're still iterating on it, but if keen to try things out, you can enable as follows: Text header Applied changes are now displayed inline. The new and can now be used to change the session mode. You can now find out what capabilities and session modes are supported by your agent. Expand either of the two sections. Tired of pressing and to accept changes from the diff buffer? Now just press from the diff viewer to accept all hunks. Same goes for rejecting. No more and . Now just press from the diff buffer. We get a new basic transient menu. Currently available via . We got lots of awesome pull requests from wonderful folks. Thank you for your contributions! Beyond what's been showcased here, much love and effort's been poured into polishing the experience. Interested in the nitty-gritty? Have a look through the 173 commits since the last blog post. If agent-shell or acp.el are useful to you, please consider sponsoring its development. LLM tokens aren't free, and neither is the time dedicated to building this stuff ;-) Arthur Heymans : Add a Package-Requires header ( PR ). Elle Najt : Execute commands in devcontainer ( PR ). Elle Najt : Fix Write tool diff preview for new files ( PR ). Elle Najt : Inline display of historical changes ( PR ). Elle Najt : Live Markdown transcripts ( PR ). Elle Najt : Prompt session mode cycling and modeline display ( PR ). Fritz Grabo : Devcontainer fallback workspace ( PR ). Guilherme Pires : Codex subscription auth ( PR ). Hordur Freyr Yngvason : Make qwen authentication optional ( PR ). Ian Davidson : Embedded context support ( PR ). Julian Hirn : Fix quick-diff window restoration for full-screen ( PR ). Ruslan Kamashev : Hide header line altogether ( PR ). festive-onion : Show Planning mode more reliably ( PR ).

0 views
xenodium 1 weeks ago

time-zones now on MELPA. Do I have your support?

A little over a week ago, I introduced time-zones , an Emacs utility to easily check city times around the world. Today, I'm happy to report, the package has been accepted into MELPA . It's been wonderful to see how well time-zones was received on Reddit . ✓ You asked for MELPA publishing and I delivered . ✓ You asked for DST display and I delivered . ✓ You asked for a UTC picker and I delivered . ✓ You asked for UTC offset display and I delivered . ✓ You asked for Windows support and I delivered . ✓ You asked for help and bug fixes and I delivered . Bringing features and improving our beloved text editor takes time and effort. isn't my first package, I've also published a bunch of Emacs packages . Will you help make this work sustainable ?

0 views
xenodium 2 weeks ago

Bending Emacs - Episode 4: Batch renaming files

I'm now a few weeks into my Bending Emacs series. Today I share a new episode. Bending Emacs Episode 4: Batch renaming files In this video, I show a few ways of batch renaming files. The covered flows are: Liked the video? Please let me know. Got feedback? Leave me some comments . Please go like my video , share with others, and subscribe to my channel . If there's enough interest, I'll continue making more videos! Enjoying this content or my projects ? I am an indie dev. Help make it sustainable by ✨ sponsoring ✨ Need a blog? I can help with that . Maybe buy my iOS apps too ;) Dired editable buffers . Multiple cursors using region-bindings-mode to insert numbers via # (I had a tiny blog entry on this). We can batch rename using Keyboard Macros too and insert numbers via macro counters . While I typically use multiple cursors for batch renaming files, I also experimented with dwim-shell-command via M-x dwim-shell-commands-rename-all .

0 views
xenodium 2 weeks ago

Emacs time-zones

Emacs ships with a perfectly functional world clock, available via . Having said that, there are two things I wish it had: As far as I can tell, these are neither available nor possible on the built-in (please correct me if otherwise), so when my friend across the world recently asked me for the best time to meet, I knew this was the last nudge I needed to get this done. With that, I give you (now on GitHub ). There isn't much to talk about other than accomplishes the above tasks very easily without resorting to writing elisp nor accessing via customize, which I seldom use. As I mentioned, is on GitHub if you'd like to give it a spin. It's super fresh, so please report any issues. Hope you like it. Reckon will be useful to you? Enjoying this blog or my projects ? I am an indie dev. Help make it sustainable by ✨ sponsoring ✨ Need a blog? I can help with that . Maybe buy my iOS apps too ;) A quick way to interactively add any city (bonus points for fuzzy search). An easy way to shift the time back and forth.

0 views
xenodium 3 weeks ago

Bending Emacs - Episode 3: Git clone (the lazy way)

Continuing on the Bending Emacs series, today I share a new episode. Bending Emacs Episode 03: Git clone (the lazy way) In this video, I show my latest iteration on an expedited git clone flow. If this topic sounds familiar, I covered it back in 2020 with my clone git repo from clipboard post. My git clone flow consists of copying a git repo URL to the clipboard and subsequently invoking . Everything else is taken care of for you. I've revisited this command and added a couple of improvements: Configurability (via ). For example: Optional prefixes to change function behavior Automatically place point/cursor at README file. I was going to post the snippet here, though may as well point you over to GitHub where is more likely to remain up-to-date. Note that is now optionally available as part of my dwim-shell-command package. Liked the video? Please let me know. Got feedback? Leave me some comments . Please go like my video , share with others, and subscribe to my channel . If there's enough interest, I'll continue making more videos! Configurability (via ). For example: Optional prefixes to change function behavior : Pick target location . : Pick any directory. Automatically place point/cursor at README file.

0 views
xenodium 3 weeks ago

agent-shell 0.5 improvements

While it's only been a few weeks since introducing Emacs agent-shell , we've landed nearly 100 commits and enough improvements to warrant a new blog post. agent-shell now includes support for two additional ACP-capable agents: In addition to starting new shells via agent-specific commands, we now have a unified entry point, enabling selection from a list of supported agents. The agent-specific commands remain available as usual: now provides basic control to toggle display of shell buffers: While provides basic display toggling, Calum MacRae offers a comprehensive sidebar package. Check out agent-shell-sidebar . now has experimental support for running agents inside dev containers. See docs . buffers, proposing changes, get a more polished experience. More notably, diffs get context (thanks to David J. Rosenbaum), single-key patch navigation/acceptance, and file names now displayed in header line. Environment variables can now be loaded from either the Emacs environment, .env files, and/or overridden inline: Different authentication methods are now supported. For example: Check per provider, as available options may differ. On the smaller side, but also contributing to overall polish: While not technically part of , acp.el 's traffic inspection has been getting some love to help users diagnose issues. Thank you for your contributions! Thank you to all sponsors. While LLMs aren't everyone's cup of tea, we're seeing editors across the board evolving to accommodate these new LLM tools. In a somewhat similar vein, LSP integration wasn't for everyone, but for those who did want it, Emacs luckily catered to them. Thank you for helping make this project sustainable while also enabling Emacs to cater to all. If agent-shell or acp.el are useful to you, consider sponsoring its development. LLM tokens aren't free, and neither is the time dedicated to building this stuff ;-) Claude Code Codex via codex-acp (new) Goose (new) : Toggles display of the most recently accessed agent (per project). : Controls how agent shells are displayed when activated. Single-key permission bindings (y/n/!). Improved error messages. Improved task status rendering. Improved TAB navigation. David J. Rosenbaum: Context support in diffs ( PR ). Fritz Grabo: Dev container support ( PR ). Grant Surlyn: Doom Emacs installation instructions ( PR ). Mark A. Hershberger: Goose key improvement ( PR ). Ruslan Kamashev: Customization group fix ( PR ).

0 views
xenodium 1 months ago

Bending Emacs - Episode 2: From vanilla to your flavor

While still finding my footing making Emacs videos, today I'm sharing my second video. Bending Emacs Episode 02: From vanilla to your flavor The video is a little longer than I intended at 14:37, so plan accordingly. In this video, I show some of my favorite UI customizations, with additional tips and tricks along the way. Like my first video, I'm hoping you find unexpected goodies in there despite being familiar with the general topic. Read on for all supporting material… Showcased a handful of ways to evaluate elisp. M-x eval-last-sexp M-x eval-expression M-x eval-buffer M-x org-ctrl-c-ctrl-c (Evaluate org source blocks) Sample snippets: other-emacs.el (minimal, almost vanilla setup): We want to extend source blocks to accept the header argument as follows: So we advice : No text in title bar Transparent titlebar (macOS) A little static welcome screen I cooked up. Liked the video? Please let me know. Got feedback? Leave me some comments . Please go like my video , share with others, and subscribe to my channel . If there's enough interest, I'll continue making more videos! M-x eval-last-sexp M-x eval-expression M-x eval-buffer M-x org-ctrl-c-ctrl-c (Evaluate org source blocks) Sample snippets: M-x describe-function (built-in). M-x helpful-callable (via third-party helpful package).

0 views
xenodium 1 months ago

Bending Emacs - Episode 1: Applying CLI utils

While most of the content I share is typically covered in blog posts, I'm trying something new. Today, I'll share my first episode of Bending Emacs. This video focuses on how I like to apply (or batch-apply) command line utilities. While the video focuses on applying command line utilities, here's a list of all the things I used: Liked the video? Please let me know. Got feedback? Leave me some comments . Please go like my video , share with others, and subscribe to my channel . If there's enough interest, I'll make more videos! Org mode for the presentation itself. ffmpeg does the heavy lifting converting videos to gifs. Asked Claude for the relevant command via chatgpt-shell 's . Browsed the video directory via dired mode. Previewed video thumbnails via ready-player mode. Previewed gifs via image mode 's . Validated the command via eshell . Applied a DWIM shell command via . Duplicated files from via .

0 views
xenodium 1 months ago

Introducing Emacs agent-shell (powered by ACP)

Not long ago, I introduced acp.el , an Emacs lisp implementation of ACP ( Agent Client Protocol ), the agent protocol developed between Zed and Google folks . While I've been happily accessing LLMs from my beloved text editor via chatgpt-shell (a multi-model package I built), I've been fairly slow on the AI agents uptake. Probably a severe case of old-man-shouts-at-cloud sorta thing, but hey I want well-integrated tools in my text editor. When I heard of ACP, I knew this was the thing I was waiting for to play around with agents. With an early acp.el client library in place, I set out to build an Emacs-native agent integration… Today, I have an initial version of agent-shell I can share. is a native Emacs shell, powered by comint-mode (check out Mickey's comint article btw). As such, we don't have to dance between char and line modes to interact with things. is just a regular Emacs buffer like any other you're used to. Thanks to ACP, we can now build agent-agnostic experiences by simply configuring our clients to communicate with their respective agents using a common protocol. As users, we benefit from a single, consistent experience, powered by any agent of our choice. Configuring different agents from boils down which agent we want running in the comms process. Here's an example of Gemini CLI vs Claude Code configuration: I've yet to try other agents. If you get another agent running, I'd love to hear about it. Maybe submit a pull request ? While I've been relying on my acp.el client library, I'm still fairly new to the protocol. I often inspect traffic to see what's going on. After staring at json for far too long, I figured I may as well build some tooling around acp.el to make my life easier. I added a traffic buffer for that. From , you can invoke it via . Developing against paid agents got expensive quickly. Not only expensive, but my edit-compile-run cycle also became boringly slow waiting for agents. While I knew I wanted some sort of fake agent to work against, I didn't want to craft the fake traffic myself. Remember that traffic buffer I showed ya? Well, I can now save that traffic to disk and replay it later. This enabled me to run problematic sessions once and quickly replay multiple times to fix things. While re-playing has its quirks and limitations, it's done the job for now. You can see a Claude Code session below, followed by its replayed counterpart via fake infrastructure. Getting here took quite a bit of work. Having said that, it's only a start. I myself need to get more familiar with agent usage and evolve the package UX however it feels most natural within its new habitat. Lately, I've been experimenting with a quick diff buffer, driven by n/p keys, shown along the permission dialog. While I've implemented enough parts of the Agent Client Protocol Schema to make the package useful, it's hardly complete. I've yet to fully familiarize myself with most protocol features. Both of my new Emacs packages, agent-shell and acp.el , are now available on GitHub. As an agent user, go straight to agent-shell . If you're a package author and would like to build an ACP experience, then give acp.el a try. Both packages are brand new and may have rough edges. Be sure to file bugs or feature requests as needed. I've been heads down, working on these packages for some time. If you're using cloud LLM services, you're likely already paying for tokens. If you find my work useful, please consider routing some of those coins to help fund it. Maybe my tools make you more productive at work? Ask your employer to support the work . These packages not only take time and effort, but also cost me money. Help fund the work .

0 views
xenodium 1 months ago

Introducing acp.el

I recently shared my early Emacs experiments with ACP , the Agent Client Protocol now supported by Gemini CLI and Claude Code LLM agents. While we can already run these agents from Emacs with the likes of vterm , I'm keen to offer an Emacs-native alternative to drive them. To do that, I'm working an a new package: (more on this to be shared soon). While this new Emacs agent shell has an opinionated user experience, it uses ACP under the hood. Being a protocol, it's entirely UI-agnostic. For this, I now have an early version available of the acp.el library. implements Agent Client Protocol for Emacs lisp as per agentclientprotocol.com . While this library is in its infancy, it's enabling me to carry on with my work. lives as a separate library, is UI-agnostic, and can be used by Emacs package authors to build the their desired ACP-powered agent experience. You can instantiate an ACP client and send a request as follows: I'm new at using ACP myself, so I've added a special logging buffer to which enables me to inspect traffic and learn about the exchanges between clients and agents. You can enable logging with: Look out for the buffer, which looks a little like this: If you're keen to experiment with ACP in Emacs lisp and build agent-agnostic packages, take a look at ( now on GitHub ). As mentioned, it's early days for this library, but it's a start. Please file issues and feature requests. If you build anything on top of , lemme know. I'd love to see it in action. I'm working on two new Emacs packages: acp.el (introduced in this post) and (I'll soon share more about that). Please help me make development of these packages sustainable . These packages take time and effort, but also cost me money as I have to pay for LLM tokens throughout testing and development. Please help fund it .

0 views
xenodium 2 months ago

So you want ACP (Agent Client Protocol) for Emacs?

Last week, I was delighted to see the Zed editor shipping beta support for their Claude Code integration . Being an Emacs enthusiast, you may wonder about my excitement. In their demo, the Zed team mentioned the integration is now possible thanks to Agent Client Protocol (ACP) , which they developed in collaboration with Google. This is great news for Emacs users, as it opens the possibilities for deeper native agent integrations in our beloved editor. You can think of ACP as LSP but for LLM agents. While I have a bunch of LLM models integrated into chatgpt-shell (including local ones ), I've yet to make much headway into enabling the models to access smarter context (ie. filesystem or local tools), beyond my initial tool calling experiment . Somehow, I wasn't super excited about tool calling, as it felt like these integrations would fall short when compared to more advanced agents like Anthropic's Claude Code or Google's Gemini CLI . In fact, I haven't been that enthusiastic about these agents, since they offered relatively little API surface to enable deeper Emacs integration (which is where I live!). That is, until ACP came along. With ACP in mind, I'm much more likely to get on board with Emacs-agent integrations. I can now delegate all that complex agent logic to external tools and focus on building a great Emacs experience I'd be happy with. And with that, I had an initial go at prototyping a bare minimum but with enough UX shell goodies to get me excited about it. I chose Gemini for this prototype. You can see it all in its minimal glory: While getting the initials kinda working was relatively straightforward (with everything I already know about building chatgpt-shell), adding support for all ACP features with a delightfully polished Emacs experience will take a bunch of effort. While I'm excited about the prospects, dedicating a chunk of my time to make this happen isn't super feasible. You may have noticed more Emacs-related work/posts from me lately. This is currently possible because I've gone full indie dev. The flexibility is great, but doing Emacs things isn't exactly gonna help pay the bills unless interested folks help fund/support the effort . My shell packages have quite a few enthusiastic users who more often than not, are using my package to talk to paid cloud services from the likes of OpenAI, Anthropic, or Google. I'm looking at you folks! I understand you're sending money to these companies who are providing you with a great service, but also remember the lovely Emacs integrations you use, which also need funding (much more than these well-funded commercial entities). While I'm a fan of chat-like Emacs shells for LLM/agents and would like to build a new agent shell, I also want to dedicate a chunk of this effort to building a UX-agnostic ACP Emacs library (acp.el). This library could be leveraged by me or any other Emacs package author. Enough to take your wallets out and help fund it ?

0 views
xenodium 2 months ago

Diverted mode

James Dyer and I both ran into the same workflow snag when fixing source indentation . He explains it best: Naturally, this is Emacs and were both able to patch our editor to smoothen things out. While I ran into the same snag after selecting an entire buffer (via ), I also faced it with and er/expand-region (awesome package btw). With three cases in mind, I wanted a somewhat generic solution, so I built diverted.el , a little minor mode to identify these momentary diversions and try to bring the point back to the original location. Mind you, this was back in 2019 and until James's post, I hadn't heard of anyone else running into a similar snag. Since then, I kept the package as part of my config. James's post gave me the nudge I needed to move out of my config and into its own GitHub repo . By default, recognizes both and as diversions, but you can also recognize the likes of via . I'm hoping configuring is fairly self-explanatory. To date, I only have , , and as recognized diversions. Read on for a little demo… Notice how point is left at the top of the screen after pressing TAB to indent region. Notice how point is left where it was prior to selecting the function and pressing TAB to indent region. That's it for today. If you want to give a try, head over to GitHub . Reckon will be useful to you? Enjoying this blog or my projects ? I am an 👉 indie dev 👈. Help make it sustainable by ✨ sponsoring ✨ Need a blog? I can help with that . Maybe buy my iOS apps too ;) You’re working in a file with inconsistent indentation You want to fix the entire buffer’s formatting You run C-x h (select all) followed by M-x indent-region Your mark is now at the beginning of the buffer, disrupting your workflow

0 views
xenodium 2 months ago

Who moved my text?

I had an annoying chatgpt-shell bug where sometimes the compose buffer's svg header would disappear while text was streaming into the Emacs buffer. There are a number of things that could have gone rogue when streaming and post-processing buffer text, so I wasn't quite sure where to start narrowing things down. I had a feeling I could maybe use something like hook to monitor changes, but that only tells me about the text modified. I wanted to know which of my functions triggered the change, so maybe I could print a few frames from the stack? So that's what I did… Here's an extract from the logs: Buffer claude llm (sonnet-4/Programming)> compose changed: 496-498 | Stack: (backtrace-frames mapcar let my-change-tracker insert save-excursion let save-current-buffer progn if #[(output) ((setq output (or output )) (if (buffer-live-p buffer) (progn (save-current-buffer (set-buffer buffer) (let ((inhibit-read-only t)) (save-excursion (if orig-region-active (progn (delete-region region-beginning region-end) (setq orig-region-active nil))) (goto-char marker) (insert output) (set-marker marker (+ (length output) (marker-position marker))))))))) ((region-end) (region-beginning) (orig-region-active) (marker . #<marker at 496 in *claude llm (sonnet-4/Programming)> compose*>) (buffer . claude llm (sonnet-4/Programming)> compose ))] shell-maker–write-reply… After increasing the number of logged frames, I started seeing bits of my code and… bingo! I found a very suspicious . After spotting this, fixing the bug was trivial. While the bug was annoying, I had been procrastinating on fixing as it could have been a number of things. In this case, printing frames from turned out perfect for narrowing things down. I'll be keeping this in the toolbox. Maybe it can help you too. Learned something new? Enjoying this blog or my projects ? I am an 👉 indie dev 👈. Help make it sustainable by ✨ sponsoring ✨ Need a blog? I can help with that . Maybe buy my iOS apps too ;)

0 views
xenodium 2 months ago

Dired buffers with media overlays

It's been well over a year now since I've moved most of my music consumption away from streaming. I started purchasing music again, just so I can play offline at any time (and on my terms). That's not so say I don't stream, but that's now purely reserved for discovery. Most playback happens via Ready Player Mode , a little Emacs player I built when I decided to take playback offline. This post isn't so much about Ready Player and more about a recent dired experience. I had a directory with a handful of mp3s, which I wanted to split into separate album subdirectories. The challenge being the mp3 file names did not include album names. Sorting this out isn't a big task for a music-organization tool, but my brain quickly went hmmm… if dired displayed album metadata, I could just use that to quickly guide me through all the file management I needed. After all, I already know how to use ffprobe to extract relevant metadata, so I could just enhance dired's listing to also show me metadata as overlays. dired-git-info does just that. With that, ready-player-dired-mode was born. After enabling with , I can easily get on with my tiny file reorg without any procrastination whatsoever . I've just pushed ready-player-dired-mode to Ready Player's GitHub repo . It's pretty fresh, so you may (or may not) encounter rough edges. Is Ready Player useful to you? Enjoying this blog or my projects ? I am an 👉 indie dev 👈. Help make my work sustainable by ✨ sponsoring ✨ Need a blog? I can help with that . Maybe buy my macOS/iOS apps too ;)

0 views
xenodium 2 months ago

Brisket recipe

On a whim, after seeing a random brisket picture online, I decided today was the day to make my first brisket. Rinse and pat dry. Salt both sides and sear. Crush spices, mix, and apply the rub generously all over the surface of the brisket, pressing gently to ensure it adheres. Wrap up in baking paper, place on tray, and wrap with foil. Bake at 120°C. Roughly 2-3 hours per kilo. 15g Kosher salt (coarse) 15g Black pepper (coarsely ground) 10g Smoked paprika 5g Chipotle powder 5g Onion granules 5g Garlic granules 2g Cumin seeds, toasted and ground 2g S&B hot mustard powder 5g Brown sugar

0 views
xenodium 2 months ago

A tiny upgrade to the LLM model picker

A little while ago, I added an info header to chatgpt-shell 's compose buffer. It displays the current model's icon, using the lovely Lobe Icons 🥨 . With that in place, it was only a matter of time until got a similar upgrade in my Emacs package. As of chatgpt-shell v2.30.1, you can get the upgrade too. If you prefer to keep graphics out of model-picking, I got you covered. Set to . Is chatgpt-shell useful to you? Enjoying this blog or my projects ? I am an 👉 indie dev 👈. Help make my work sustainable by ✨ sponsoring ✨ Need a blog? I can help with that . Maybe buy my macOS/iOS apps too ;)

0 views
xenodium 2 months ago

Emacs elevator pitch

Me: Have you heard of Emacs? Me: On the surface, it looks like a text editor… Me: But really, it's more like a gateway to a world moulded to your needs. Me: Emacs ships with an RPN calculator and even a doctor . Me: Naturally, it doesn't do everything I want it to do nor how I want it to. Me: Luckily, I can throw elisp at it and make it do things my way. Stranger: Huh?? Me: Emacs didn't quite do all the things I wanted it to, so… Me: I made it play music how I wanted it to . Me: Control my operating system ( 1 , 2 , 3 , 4 ). Me: Help me learn Japanese . Me: Trim videos … or video screenshots . Me: Talk to the LLM robots ( 1 , 2 ). Me: Preview SwiftUI layouts . Me: Batch-apply all sorts of utils . Me: Send notes to my Kindle . Me: Tweak the debugger . Me: Enhance my shell . Stranger: ??!? Me: Do what I mean . Me: Tweak my email client ( 1 , 2 ). Me: Bring closer macOS integration ( 1 , 2 , 3 , 4 ). Me: Scan QR codes . Me: Record Screencasts . Me: Build iOS apps . Me: Blog about all sorts of things . Me: Tailor completion . Me: Easily clone repos . Me: Use my preferred eye candy . Me: Evaluate Objective-C code . Stranger: Sir… Me: Write however I want . Me: Stitch images . Me: Make multiple cursors do what I want . Me: Make searching smarter . Me: Look up where I took photos . Me: SQLite feel like a spreadsheet . Me: Easily insert SF Symbols . Me: Build an emotional zone . Me: Tweak my file manager ( 1 , 2 , 3 ). Me: Generate documentation . Me: Gosh, I could keep going… Stranger: Sir this is a Wendy's . This post is part of the Emacs Carnival . This month is Your Elevator Pitch for Emacs, hosted by Jeremy Friesen . Learned something new? Enjoying this blog or my projects ? I am an 👉 indie dev 👈. Help make it sustainable by ✨ sponsoring ✨ Need a blog? I can help with that . Maybe buy my iOS apps too ;)

0 views
xenodium 2 months ago

Emacs as your video-trimming tool

Marcin ‘mbork’ Borkowski has a nice post showing us how he trims video clips from our beloved editor . Trimming clips is something I do from time to time, specially when posting a screencast of sorts. Since I don't need much, I typically resort to QuickTime Player's trimming functionality that ships with macOS. While it does the job, ever since I added a "graphical" seeker to Ready Player Mode , I had been meaning to build a simple video trimming tool of sorts. Marcin's post was just about the right nudge I needed to also give this a go, yielding video-trimmer-mode . The solution relies on ffmpeg to do the heavy lifting and is roughly 300 lines of code. I was going to share the entire snippet in this post, though may as well point you to its repo . I'm likely to tweak it, so you may as well take a look at its latest incarnation. Find video-trimmer-mode useful? Want me to publish to MELPA ? Enjoying this blog or my projects ? I am an 👉 indie dev 👈. Help make my work sustainable by ✨ sponsoring ✨ Need a blog? I can help with that . Maybe buy my macOS/iOS apps too ;)

0 views
xenodium 3 months ago

macOS dictation returns to Emacs (fix merged)

macOS apps typically benefit from built-in voice dictation input (included as a macOS freebie), with little to no additional work required from app developers. Emacs had supported this capability until relatively recently, when we began seeing reports that dictation was no longer available as of Emacs 30 . While I have no direct experience with macOS dictation-related APIs, I bisected Emacs 30 changes affecting macOS-related code (typically Objective-C code with .m file extensions). This led me to a seemingly harmless change introducing NSTextInputClient, intended to remove a deprecation warning. From that change onwards, dictation stopped working. Reverting the change did indeed bring dictation back, but at the cost of re-introducing the deprecation warning. Looking closer at the current NSTextInputClient implementation, I noticed some stubbed-out methods. In particular, stood out: Turns out implementing is all it took to bring dictation back: Implementing didn't just bring dictation back, but now leverages a newer macOS dictation implementation. You can see the slight differences in UI. I've since submitted a patch upstream . I'm happy to report that as of today, the patch is now merged into master . Thank you Gerd Möllmann and Eli Zaretskii for your help! Also big thanks to Stephen Englen, Fritz Grabo, @veer66 and @dotemacs on the fediverse who quickly jumped in to help validate the fix . While we've yet to find out when the next Emacs release will ship, we at least know the fix is coming! If like me, you'd like to get the fix backported to Emacs 30, I've shown you how to do just that on Emacs Plus (my favourite macOS build). Glad macOS dictation is fixed? Enjoying this blog or my projects ? I am an 👉 indie dev 👈. Help make my work sustainable by ✨ sponsoring ✨ Need a blog? I can help with that . Maybe buy my macOS/iOS apps too ;)

0 views
xenodium 3 months ago

Writing experience: My decade with Org

While I missed Emacs Carnival 's Take two , with this month's prompt being Writing Experience , I figured I may have a thing or two to share about my Org adoption. Org mode is often regarded as one of the indispensable Emacs features. A Swiss army of sorts enabling outlining, presentations, task management, agenda, note-taking, blogging, literate programming, the list goes on… At its core, Org features are powered by a versatile markup. Kinda like Markdown but on steroids. When starting with Org, it's easy to feel lost in the overwhelming sea of features . Luckily, we don't have to know or understand all of Org to get started nor ever need to. You get to pick and use what's useful to you at any given time. Want to get started with outlines? Easy. Let's say you wanted to start collecting python idioms, you can start with an entry like: That's precisely what I did when I started using Org nearly 12 years ago. I created a notes file and added my first entry to collect python 2 idioms . While the idioms may be outdated by now (who knows, it's been many years since I've written any significant amount of python code), but hey that's besides the point. I wanted to start a personal notes file and Org sounded awesome for that. Over time, my notes file grew in usefulness. The more I wrote, the more I could recall with search. That is, until I was away from my computer. At that point, I figured I could just export my notes to HTML (via ) and post online. Over time, folks started reaching out about something read in my notes, and so by then I suppose I had accidentally become a blogger. In 12 years of "blogging", my approach hasn't changed much. I still write to the very same Org file (beware it's big) I started writing notes to. I found this approach fairly accessible, with little ceremony. When I want to write, I open the usual text file and just write. It wasn't until fairly recently I learned this is often referred to as " one big text file " (OBTF). My HTML exporting evolved into hacky elisp cobbled together over time. While the code was nothing to rave about, it did the job just fine for well over a decade. Having said that, it was more of an "it works on my machine" sorta thing. Last year, I finally decided to change my blogging approach and built a blogging platform (in 2024?! I know right?!). Well, the modern web has led us to a sea of tracking, bloat, advertising, the list goes on… I wanted to offer a lightweight blogging alternative with none of the typical crummy bits, so I built LMNO.lol . Today, my xenodium.com blog runs off that. LMNO.lol is powered by Markdown. Wait, what? You may be wondering why an Org fan would build a blogging platform powered by a different markup? In a nutshell, reach. While I remain a faithful Org fan for its capabilities, if I want my blogging platform to appeal to more users, I can't ignore the fact that today Markdown is the prevalent format. Having said that, I wasn't about to give up on Org for personal use. I can actually have my cake and eat it too. You see, I continue writing to Org and convert to Markdown before uploading to LMNO.lol via pandoc , the Swiss Army tool of file converters. As you know, my Org adoption started with a very simple outline intended for personal notes, but we know Org is a universe of its own . I soon learned about Org tables . I'd keep finding really handy Org tips here and there. Like converting csv to Org by merely selecting the text from my beloved editor. We mentioned Org handling task management, amongst many other things. In a nutshell, tasks in Org are "simple TODO lists", using special keywords. I got started with Org tasks with something like this: I say "simple TODO lists" (in quotes) because Org task management is a another universe of its own. You can schedule tasks in all sorts of ways (like recurring), as habits, tag them, refile them, etc. and even get a nice agenda view to interact with. I don’t have an agenda post on this myself, but Christian Tietze has a wonderful write-up showcasing an improved Org-mode agenda display . Moving on from task management, I soon discovered babel , another Org super power enabling you to include code snippets. Not too different to Markdown, but I found the ability to evaluate/execute snippets and capture output pretty magical. At the time, I was writing a fair bit of Objective-C code but found babel support was missing. By looking at and , I figured how to add Objective-C support . Surprisingly, it took very little code and I could now execute Objective-C code just like python from the comfort of an Org buffer. With Org code blocks (and babel superpowers), I soon found myself including lots of snippets in my notes. I tried different different input mechanisms and eventually settled on writing my own company completion backend . company-org-block is available on GitHub and MELPA . Later on, with Michael Eliachevitch 's help, we got org-block-capf going. I continued having fun with Org babel. You can combine source blocks for different purposes, so I used it to fetch and plot Fitbit data via Gnuplot . Having learned that babel can generate images (like Gnuplot ), I figured I could have fun with SwiftUI too and built ob-swiftui . Also on MELPA . Notes aren't complete without links to references. I was already using a keyboard shortcut of sorts, but I figured I could make it much smarter . As in DWIM : Do what I mean. Like automatically fetching link title from the web and other things. Comments in posts can be a great source of recommendations (someone asking for books, blogs, etc), so I figured I could get Emacs to extract all links from an online post and dump them to an org file . Cause you never know when you're gonna need it, I randomly saved a snippet to change your MAC address from the comfort of your Org notes . Execute via . By the way, noticed the header? It enables executing the snippet as root. Having built a handful of Emacs packages, maintaining a README.org documenting commands available (and keeping it up-to-date) was a bit of a chore. I figured you could automate things and generate a nice Org table documenting your package commands and customizable variables . When you see this table in my GitHub project, you now know how it was generated. While Org babel's noweb support isn't super widely known, I learned it's great for glueing org babel blocks . I love how Org knowledge (and Emacs benefits really) just keep compounding. I started by just writing a simple Org outline. Remember? In 2023, I started experimenting with LLMs and Emacs integrations . Naturally, I had to add babel support too, so ob-chatgpt-shell ( MELPA ) and ob-dall-e-shell ( MELPA ) were added to the mix . Your knowledge base is only as useful as its wealth. The more you write, the better. And of course, the less friction, the more likely you are to write more. Org capture is super useful to save your thoughts quickly into an Org file. You can come up with all sorts of templates to expedite the process. In addition to the base structure, I figured I could automatically capture my current location, date, time, and weather as part of a note. There are no shortages of Emacs packages leveraging Org mode to give presentations ( org-present is one of many). I often enjoy David Wilson 's videos . In this one, he shares his presentation setup . I figured it'd be fun to experiment with to spiff things up . I wanted a sort of smart navigation where items are automatically expanded and collapsed as I my way through a presentation. With my Org usage growing, I felt like I was missing Org support outside of Emacs. Web access to my blog wasn't enough. I wanted to quickly capture things while on the go, so I started building iOS apps revolving around my Emacs and Org usage. Journelly is my latest iOS app, centered around note-taking and journaling. The app feels like tweeting, but for your eyes only of course. It's powered by Org markup, which can be synced with Emacs via iCloud. Org habits are handy for tracking daily habits. However, it wasn't super practical for me as I often wanted to check things off while on the go (away from Emacs). That led me to build Flat Habits . While these days I'm using Journelly to jot down just about anything, before that, I built and used Scratch as scratch pad of sorts. No iCloud syncing, but needless to say, it's also powered by Org markup. For more involved writing, nothing beats Emacs Org mode. But what if I want quick access to my Org files while on the go? Plain Org is my iOS solution for that. While I already mentioned LMNO.lol , it's been heavily inspired by my Org workflow. You write your notes or blog posts to a single plain text file, sprinkling Markdown this time around, and just drag and drop it to the web. LMNO.lol takes care of the rest. While there is newer content out there, I did capture a handful of Org bookmarks at some point. This one took me down memory lane . Sacha Chua used make these really fun videos interviewing Emacs folks, often discussing their Emacs configs. I learned a ton from these videos. That time, Sacha interviewed Howard Abrams . Gosh, that was over 10 years ago. Off the top of my head, Karl Voit also comes to mind, for championing Org for years . I know I'm not doing it justice. There are far too many folks I've learned from, who kindly share their knowledge. I've bookmarked some of them in the past. Naturally, my Org journey wouldn't be possible without Org mode itself and the incredible work from the authors and maintainers. I've personally donated to their cause and even got my ex-employer to donate multiple times. You could argue my Org usage is fairly random. Maybe it is. I'd say it's more organic than anything. I more or less started writing outlines and TODO lists, incrementally adopting whatever needed over time. It's up to you how much or little Org you adopt. Whatever you pick is the right answer for you. The Org feature set is just so vast. Some of the things I've tried didn't stick for me like plotting ledger reports or combating spam through Org, but by trying things I got to discover other things that probably did stick. I could keep going, showing you more examples of the things I discovered, but in such a vast universe what's useful to me may not be useful to you. With such a diverse toolbox, it's highly likely you'll find just the right tool for your needs. Ok, we get it. The feature set is rich. But most importantly, your data is saved in plain, transparent text, easily accessible to other tools. Heck, I even wrote my own iOS apps to view and edit Org files on the go. In over ten years of using Org, I've never lost access to my data, and I never will. That alone is the non-negotiable cherry on the cake. Learned something new? Enjoying this blog or my projects ? I am an 👉 indie dev 👈. Help make it sustainable by ✨ sponsoring ✨ Need a blog? I can help with that . Maybe buy my iOS apps too ;)

0 views