Irreal: Using Org-mode To Capture and Report Git Commits

Like most developers, Andrea Richiardi has a certain amount of logging and reporting he has to do to document his work. One such item is a report on the commits he’s made while working on various tickets. He wants to capture:

  1. The ticket number,
  2. The text of the commit description, and
  3. The time and date of the commit.

At the end of the week we wants to generate a report containing all this information.

He manages this with Org-mode and a bit of custom Elisp. He describes the solution in his post Build your productivity tools with org-mode. Almost all the work is done by the built-in Org capture and agenda functionality. Most of the Elisp is simply a couple of regular expressions that retrieve the ticket number and commit description. The only non-obvious Elisp deals with capturing the text of the commit buffer or, possibly, a selected region of text.

The template he uses for capturing the data formats it, adds some metadata, and stores it in an Org file. He has a custom agenda command to list the entries he’s captured that he can use to send the information on.

It’s a nice system that you may find useful but even if you don’t, it serves as an excellent example of how to leverage the built-in Org tools to make what might seem a complicated task easy.

-1:-- Using Org-mode To Capture and Report Git Commits (Post jcs)--L0--C0--January 15, 2020 06:15 PM

Jordan Besly: Better TRAMP autologin

Introduction

For those not in the know, TRAMP is one of Emacs’ killer apps. It’s a package that allows to interact with remote systems through a variety of protocols.

Such interactions include opening shells and browsing remote file trees as if they were locally mounted. You can even bounce across several machines like if it was nothing (it’s called multi-hops).

But there is one thing can break these otherwise seamless interactions: login prompts.

The Authinfo way

To get rid of them, emacs offers native support for Gnus Authinfo and .netrc files via its auth-source package:

(require 'dash)

(use-package auth-source
  :demand
  :no-require t
  :config
  (setq auth-sources (-filter #'file-exists-p '("~/.authinfo.gpg" "~/.authinfo" "~/.netrc"))))

Now you can just create a ~/.authinfo like this:

machine raspi login pi password raspberry

And then C-x f /ssh:pi@raspi:/ and it will connect automatically, yey!

…Except that sucks.

SSH keys to the rescue

Indeed passwords suck. Big time. Even more so when you have a gazillion of remote hosts to connect to.

SSH keys (aka identity files, aka certificates) are a way smarter (and in most cases safer) way to proceed.

Given you have a master key for connecting to all of your machines, just have to drop into your ~/.ssh/config:

Host *
    User eigen
    IdentityFile ~/.ssh/eigen-identity

And you could connect to any server for which this key is known for user eigen.

The PuTTY dilemma

If you’re on Windows, you’re most likely using PuTTY/plink as an SSH alternative.

TRAMP, in all its glory, supports PuTTY (use the /pscp: method, that’s the one you’re looking for).

PuTTY has an equivalent way to set a default key, via a Default Setting or through Pageant.

The former only works if you’re saving each and every of your hosts as a connection profile and access it with /plinkx:<PROFILE>:.

The latter only seems to load when launching putty.exe (GUI interface).

So here comes time for adventure insanity.

Insanity (or elisp-bind all the things)

Another cross-platform solution is to do this in pure elisp.

The trick is to enrich tramp-methods with an additional args corresponding to the identity file option (-i).

Thus we need some utils to alter those method definitions.

Click to reveal!

;; ------------------------------------------------------------------------
;; DEPS

(require 'tramp)
(require 'dash)

;; ------------------------------------------------------------------------
;; TRAMP METHODS ARGS

(defun prf/tramp/method/def/some-args/with-cert (some-args cert-arg cert)
  "Returns enriched tramp def SOME-ARGS with certificate arg.
SOME-ARGS can be of type `tramp-login-args' or `tramp-copy-args'"
  (let ((args-type (car some-args))
        (args (car (cdr some-args))))
    (add-to-list 'args `(,cert-arg ,(concat "\"" cert "\"")))
    `(,args-type ,args)))

(defun prf/tramp/method/def/with-cert-in-some-args (tramp-method-def args-type cert-arg cert)
  "Returns copy of TRAMP-METHOD-DEF with certificate arg added to ARGS-TYPE.
ARGS-TYPE can be `tramp-login-args' or `tramp-copy-args'."
  (let ((method-name (car tramp-method-def))
        (method-def-args (cdr tramp-method-def)))
    (cons method-name
          (-map-when
           (lambda (e) (equal (car e) args-type))
           (lambda (e) (prf/tramp/method/def/args/with-cert e cert-arg cert))
           method-def-args))))

;; ------------------------------------------------------------------------
;; TRAMP METHODS

(defun prf/tramp/method/def/with-cert-in-args (tramp-method-def cert-arg cert)
  "Returns copy of TRAMP-METHOD-DEF enriched with certificate arg.
Certificate arg gets added to both 'tramp-login-args and 'tramp-copy-args."
  (-> tramp-method-def
      (prf/tramp/method/def/with-cert-in-some-args 'tramp-login-args cert-arg cert)
      (prf/tramp/method/def/with-cert-in-some-args 'tramp-copy-args cert-arg cert)))

Then we can override the method definitions:

;; PuTTY
(let ((cert-path "~/my-cert.ppk")
      (putty-methods '("pscp" "plink" "plinkx" "psftp")))
  (setq tramp-methods
        (-map-when
         (lambda (e) (member (car e) putty-methods))
         (lambda (e) (prf/tramp/method/def/with-cert-in-args e "-i" cert-path))
         tramp-methods)))

;; SSH
(let ((cert-path "~/.ssh/id_dsa")
      (ssh-methods '("ssh" "sshx")))
  (setq tramp-methods
        (-map-when
         (lambda (e) (member (car e) ssh-methods))
         (lambda (e) (prf/tramp/method/def/with-cert-in-args e "-i" cert-path))
         tramp-methods)))

The beauty of this is that if your key is not known to the remote host, it would still prompt you for a password without failing.

The code can be found in package prf-tramp-method available at p3r7/prf-tramp.

-1:-- Better TRAMP autologin (Post)--L0--C0--January 15, 2020 12:00 AM

Irreal: Zamansky: ClojureScript 2

I’ve written a few posts lately about working in the Slime and Geiser environments to write and experiment with Common Lisp and Scheme code. What’s great about them is that they enable an “interactive programming” style where you can try out small code snippets to see what happens and build those small snippets into larger bodies of code. The snippets can be as small as a single expression. My two go to examples of this are the beginning of Magnar Sveen’s Web Rebels talk and Kris Jenkins video on building a Spotify client. You can find links to both of those in this post from 2013.

Of course, you can write Elisp this way too and the other great thing about Slime and Geiser is that they, too, run in Emacs. That means you can write, test, debug, and run your code from the comfort of Emacs. Why would you want to write code any other way?

Mike Zamansky has been experimenting with another language that enjoys a similar environment: ClojureScript. As with Common Lisp and Scheme, Emacs provides an interactive environment for ClojureScript: Bozhidar Batsov’s excellent Cider. In his second video on ClojureScript, Zamansky continues with the application he started in Using Emacs 63 that I wrote about here.

The video isn’t really about using Emacs but Emacs nevertheless plays a large and important role. Zamansky shows how easy it is to try things out and track down bugs while working on an application. Because Zamansky is a ClojureScript n00b, the ability to try something to see if it does what he expected and change things if it doesn’t is invaluable. It’s another example of the power of interactive programming.

The video is just short of 26 and a half minutes so you’ll definitely need to schedule some time but I found it interesting, enjoyable, and well worth time time.

-1:-- Zamansky: ClojureScript 2 (Post jcs)--L0--C0--January 13, 2020 05:33 PM

Sacha Chua: 2020-01-13 Emacs news

Links from reddit.com/r/emacs, r/orgmode, r/spacemacs, r/planetemacs, Hacker News, planet.emacslife.com, YouTube, the Emacs NEWS file and emacs-devel.

-1:-- 2020-01-13 Emacs news (Post Sacha Chua)--L0--C0--January 13, 2020 04:14 PM

Jordan Besly: Emacs is no text editor

… and that’s OK.

The Start of a Journey

first blade

You also might have gone through a phase of extensive search for the ULTIMATE VERY BESTEST TOOL for your first / next / hypothetical programming project.

To only find yourself at the middle of a battlefield.

Solutions are enumerated and compared. Everywhere you look, everybody seems to argue there is only one truth but not consensus is in sight.

You feel like you cannot proceed further until the conflict is resolved.

As far away as you look Emacs seems to be mentioned and compared against other “editors”.

But I dare say it’s unfair and reductive to consider Emacs as such.

The misconception

You’ll see it everywhere. This statement.

Emacs is an [extensible|free|customizable|bloated] text editor.

On blog posts, forums, Linux package descriptions, Wikipedia, emacs.sexy and even on the official site.

But the latter quickly rectifies with:

At its core is an interpreter for Emacs Lisp, a dialect of the Lisp programming language with extensions to support text editing.

Yeah, that seems more correct. But it resumes the implementation and not the function.

Everybody knows this Vim hooligan proverb:

Emacs is a great operating system, lacking only a decent editor.

And even though it’s humoristic (thus by design slightly incorrect) I’m more OK with this definition than with the “text editor” one.

The whys & hows

I guess that the main reason why people state that Emacs is (primarily) a text editor is to make it easier to grasp.

emacs could be anything

In fact it was not conceived as a text editor with extensibility as a feature.

Instead, Emacs was conceived as an extensible environment with text editing as a feature.

Even if this was originally a means to an end1, this important design decision has allowed Emacs to evolve into something broader.

Proposal for a definition

Let’s attempt to define Emacs’ essence:

Emacs is a generic user-centric text manipulation environment.

“Wow, that looks like the definition of a text editor!”

OK, let’s explain this gibberish.

User-centric means Emacs is built around user interactions. It needs user input (commands) to perform any actions2 and the results of those actions are presented to the user (via side-effects).

Even something as simple as moving the cursor is modelized as a command side-effecting the operation3.

Please also note that by text we target any character string, not necessarily “human-understandable words”. A more explicit term would be textual data.

User-driven actions consist of and are built upon the manipulation of said textual data.

Manipulation is a very broad term, and that’s because Emacs is very broad in its capabilities.

Indeed, it relies on generic APIs to interact with text. This abstraction allows it to interact with anything that “speaks” textual data (files, HTTP APIs, databases…).

In other words:

Emacs is a generic Man-Machine Interface for anything text.

"Wow, that still looks like the definition of an editor!"

Yes, but that’s also the the definition of a task planner, file browser, terminal emulator, email client, diffing tool4, remote server access tool (SSH, FTP…), git frontend, HTTP client / server

And Emacs is all of that. Not because it’s a bloated editor, but because it’s a generic tool for everything text-related, including editing.

A bit of nuance

This is not a glorification of Emacs.

Emacs also has it quirks that sometimes makes it painful to work with.

Some APIs are showing their age (in their design and naming conventions) and programming in elisp can genuinely feel like retro-computing.

Dynamic binding is user-friendly, but the lack of parallel threading is painful when the interface freezes5.

Our expectation of what an editor should be has evolved quite a bit over time (from text editor, to code editor to programming environment).

Emacs has managed to stay competitive thanks to its native adaptability.

With no expertise, I assume that newer kids (such as Sublime, VSCode…) got designed from the ground with levels of abstractions that make them closer to Emacs in design than older traditional text editors.

The ability to override and extend core functionalities (“they told me i could be anything”) is maybe the only thing that keeps making Emacs a different beast, but is a nightmare from a security and stability standpoint.

Closing thoughts

Emacs is my main MMI for textual data.

I’ve invested countless hours tailoring it to my needs but have saved oh-so-many more reducing otherwise repetitive tasks to a minimal amount of keystrokes performed at the speed of thought.

It has terrible defaults.

Other tools can be seen as blades that gets polished through configuration and plugins.

For Emacs a better analogy would be a rough piece of steel you’d have to extract from a stone, forge and tailor to your exact needs.

You’d have to learn its lingo and idiosyncrasies. You’d have to learn elisp. You will certainly find yourself more efficient using a collection of other tools.

But at the end of the journey you may end up with your very own Excalibur.

And this is, I believe, how Emacs should get advertised instead of as being only an “editor”.

excalibur

Notes

  1. The “end” being to build a text editing tool. 

  2. Not true as modern Emacs can do stuff independently of user input. But the implementation is often hackish (timers…). Furthermore, doing stuff programmatically rely on user-centric APIs (temp buffers, moving point and mark around…). 

  3. Just do C-h k following by any arrow key and see for yourself. 

  4. You might want to take a look at ztree in complement to ediff for recursive directory diffing. 

  5. See the “No Threading” page on the wiki 

-1:-- Emacs is no text editor (Post)--L0--C0--January 12, 2020 12:00 AM

Irreal: Emacs Modifier Keys on the Mac

If you’re an Emacs user who works primarily on some sort of Mac, you may be interested in a post by Nick Drozd in which he suggests a keyboard layout for avoiding pinky fatigue and all that goes with it. The TD;DR is that he switches the ⌘ Cmd and Ctrl keys in Emacs and then maps Caps Lock to Ctrl at the system level. That gives you a Ctrl and Meta key on both sides of the keyboard and they can both be reached with a thumb rather than a pinky finger. Drozd gives you the Emacs settings for switching Ctrl and ⌘ Cmd and, of course, you can map Caps Lock to Ctrl by clicking on the Modifier Keys button on the Keyboard pane of System Preferences→Keyboard. Drozd’s settings also map the fn key to Hyper. I’ve used that to give me a Hyper key for many years and really like it. It doesn’t interfere with the system function keys so you have the best of both worlds.

I haven’t tried this yet because I’m worried that it will mess up my muscle memory for the ⌘ Cmd key. It’s probably not a big deal so I’m still considering it. If you’re not worried about such things, give Drozd’s system a try. It’s easy to set up and easy to back out if you decide you don’t like it.

-1:-- Emacs Modifier Keys on the Mac (Post jcs)--L0--C0--January 11, 2020 05:13 PM

Irreal: The Undo-tree Bugs

One of my favorite packages is undo-tree. It makes a “many branched” sequence of changes easy to fix but to tell the truth the most valuable thing about it for me is the sensible redo functionality. It’s always worked perfectly for me and is a valuable tool in my Emacs toolkit.

Oddly, though, I keep seeing tweets and blog posts about it being unreliable. Given my success with it, I didn’t pay too much attention to the reports of errors but did wonder if there was anything to them. Now the author, Toby Cubitt, has published a very informative post that addresses the purported errors and what’s really going on.

Cubitt’s problem is that he couldn’t reproduce the problems and no one could provide him with a recipe for reproducing them. There were two problems. The most common was that sometimes undo-tree would report that there were no further changes to undo even though all the changes to the buffer hadn’t been undone. Finally, someone was able to provide Cubitt with a recipe for reproducing the error and Cubitt found that there was no problem with the code—it was behaving exactly as documented—but that the real issue was “user expectations.” Emacs keeps the changes on an undo ring and when the entries are exhausted, the oldest entries are overwritten. Cubitt fixed this by increasing the default size of the ring (by a factor of 1,000) and by providing a bit more feedback to the user when data is lost.

The second problem is that occasionally the undo data would get corrupted. No one has yet been able to reproduce that error but Cubitt has an hypothesis that it’s caused by a race conditions between undo-tree and Emacs’ low level garbage collection code. He made a some changes to reduce the likelihood of this happening and made a new release.

Cubitt’s post has many more details and includes a nice explanation on how undo-tree works. If you’re an undo-tree user, it’s definitely worth reading. If you’re not an undo-tree user and have been hesitating because of its purported instability, there’s no longer any reason to hesitate. As far as I’m concerned, even if Cubitt hasn’t eradicated all of the bugs, undo-tree’s benefits are more than worth an occasional error.

-1:-- The Undo-tree Bugs (Post jcs)--L0--C0--January 10, 2020 05:55 PM

Irreal: Zamansky 63: ClojureScript

Mike Zamansky has another video up in his Using Emacs Series. This video is a little different from his usual fare in that it’s more about using ClojureScript than Emacs, although Emacs does play a prominent role.

If you follow Zamansky’s blog you know that he’s been learning and experimenting with Clojure and ClojureScript lately. This video is his effort the flatten the learning curve a bit for other n00bs by explaining some of the things he had trouble figuring out. I know nothing about ClojureScript so I can’t comment intelligently on the content of the video but I did find it interesting.

I don’t do much front end work either so I also don’t know a lot about writing HTML or generating Web pages. What I found especially interesting about the video was how easy it is to make, debug, and try experimental changes with ClojureScript. If I were going to start writing Web apps, I’m pretty sure I’d prefer learning and using ClojureScript over learning and using JavaScript. Using Cider means that once you’ve got everything installed, you can work entirely in Emacs. It’s a lot like using Slime except that your “output” is going to your browser, which updates in real time as you make changes. It looks like a very comfortable environment in which to do interactive programming.

Depending on feedback, Zamansky may do some more videos on ClojureScript so if you’re interested, be sure to let him know in the comments. The video is 33 minutes, 42 seconds so you’ll need to schedule some time.

-1:-- Zamansky 63: ClojureScript (Post jcs)--L0--C0--January 09, 2020 06:43 PM

Mike Zamansky: Using Emacs 63 ClojureScript

I've been playing with ClojureScipt for my web projects recently and really like it. Much more fun than any of the JavaScript frameworks I've used. Still, getting started was somewhat difficult due to the number of options in tooling and uneven documentation and learning resources. Here's a video that shows how I use Emacs for ClojureScript development but the focus of the video is on how to get started with ClojureScript and Emacs takes a back seat other than an example of my workflow.
-1:-- Using Emacs 63 ClojureScript (Post)--L0--C0--January 09, 2020 12:11 PM

Irreal: A Palindrome Predicate Coda

As I wrote yesterday, I upgraded my Common Lisp environment to SBCL 2.0 so of course I wanted to try it out. Writing Lisp programs in the excellent Slime environment that Emacs provides is truly a pleasure that I haven’t enjoyed nearly enough lately.

The natural thing to play around with is the palindrome predicates that I wrote about last month. That code was written in Scheme and produced some surprising results. If you read and enjoyed that post, be sure to check out the comments. Chris Wellons did a deep dive into what was going on in Guile that caused the surprising results. It’s definitely worth reading if only to appreciate Wellons’ virtuosity.

I rewrote the two predicates in Common Lisp and reran the benchmarks from the original post.

(defun palindrome-r-p (str)
  "Recursive version of a palindrome predicate."
  (let ((len (length str)))
    (cond
      ((zerop len) t)
      ((= len 1) t)
      ((not (eq (aref str 0) (aref str (1- len)))) nil)
      (t (palindrome-r-p (subseq str 1 (1- len)))))))

(defun palindrome-i-p (str)
  "Interative version of a palindrome predicate."
  (do ((left 0 (1+ left))
       (right (1- (length str)) (1- right))
       (palindromep t))
      ((or (>= left right) (not palindromep)) palindromep)
    (setf palindromep (eq (aref str left) (aref str right)))))

(defconstant str (make-string 100000 :initial-element #\x))

(defun bench (rcnt f)
  "Run f rcnt times with timing."
  (time
   (do ((i rcnt (1- i)))
       ((zerop i) t)
     (funcall f str))))

with the results

SB-SPROF> (bench 10 #'palindrome-i-p)
Evaluation took:
  0.006 seconds of real time
  0.006490 seconds of total run time (0.006487 user, 0.000003 system)
  100.00% CPU
  18,167,680 processor cycles
  0 bytes consed

T

  SB-SPROF> (bench 10 #'palindrome-r-p)
  Evaluation took:
    46.223 seconds of real time
    46.627848 seconds of total run time (44.819204 user, 1.808644 system)
    [ Run times consist of 14.377 seconds GC time, and 32.251 seconds non-GC time. ]
    100.88% CPU
    129,420,331,778 processor cycles
    99,994,412,160 bytes consed

  T

The timing for the recursive version shows why I ran the loop 10 times instead of 1000 as I did with Guile.

SBCL is an industrial strength Lisp that compiles to native code and has true tail recursion so if you haven’t read Wellons’ commentary to the original post, you might be surprised at the comparative speeds. The problem, of course, is that unlike Guile, Common Lisp always allocates a new sequence for a subsequence and never shares storage with the old sequence. The problem, then, is almost certainly that each (recursive) call to palindrome-r-p is allocating new storage and copying the substring into it.

Of course, one of our cardinal commandments is to avoid statements like the last and invoke the profiler:

CL-USER> (require :sb-sprof)
("SB-SPROF")
CL-USER> (in-package :sb-sprof)
#<PACKAGE "SB-SPROF">

SB-SPROF> (with-profiling (:reset t :sample-interval .00001) (palindrome-r-p str))
Profiler sample vector full (15,506 traces / approximately 499,999 samples), doubling the size
Profiler sample vector full (31,019 traces / approximately 999,997 samples), doubling the size
T
SB-SPROF> (report)

Number of samples:   50000
Sample interval:     0.00001 seconds
Total sampling time: 0.5 seconds
Number of cycles:    0
Sampled threads:
 #<SB-THREAD:THREAD "new-repl-thread" RUNNING {1002BC7883}>

           Self        Total        Cumul
  Nr  Count     %  Count     %  Count     %    Calls  Function
------------------------------------------------------------------------
   1  34735  69.5  34735  69.5  34735  69.5        -  SB-KERNEL:UB32-BASH-COPY
   2  14592  29.2  49975  99.9  49327  98.7        -  SB-KERNEL:VECTOR-SUBSEQ*
   3    647   1.3    647   1.3  49974  99.9        -  "foreign function __pthread_sigmask"
   4      9   0.0  49997 100.0  49983 100.0        -  PALINDROME-R-P
   5      6   0.0      6   0.0  49989 100.0        -  SB-KERNEL:HAIRY-DATA-VECTOR-REF/CHECK-BOUNDS
   6      1   0.0      1   0.0  49990 100.0        -  (SB-VM::OPTIMIZED-DATA-VECTOR-REF CHARACTER)
   7      1   0.0      1   0.0  49991 100.0        -  (FLET SB-THREAD::EXEC :IN SB-KERNEL::POST-GC)
   8      1   0.0      1   0.0  49992 100.0        -  "foreign function pthread_getspecific"
   9      0   0.0  50000 100.0  49992 100.0        -  "Unknown component: #x2276F230"
  10      0   0.0  50000 100.0  49992 100.0        -  SWANK::EVAL-REGION
  11      0   0.0  50000 100.0  49992 100.0        -  (LAMBDA NIL :IN SWANK-REPL::REPL-EVAL)
  12      0   0.0  50000 100.0  49992 100.0        -  SWANK-REPL::TRACK-PACKAGE
  13      0   0.0  50000 100.0  49992 100.0        -  SWANK::CALL-WITH-RETRY-RESTART
  14      0   0.0  50000 100.0  49992 100.0        -  SWANK/SBCL::CALL-WITH-DEBOOTSTRAPPING
  15      0   0.0  50000 100.0  49992 100.0        -  SWANK::CALL-WITH-BUFFER-SYNTAX
  16      0   0.0  50000 100.0  49992 100.0        -  SWANK-REPL::REPL-EVAL
  17      0   0.0  50000 100.0  49992 100.0        -  SIMPLE-EVAL-IN-LEXENV
  18      0   0.0  50000 100.0  49992 100.0        -  EVAL
  19      0   0.0  50000 100.0  49992 100.0        -  SWANK:EVAL-FOR-EMACS
  20      0   0.0  50000 100.0  49992 100.0        -  SWANK::PROCESS-REQUESTS
  21      0   0.0  50000 100.0  49992 100.0        -  (LAMBDA NIL :IN SWANK::HANDLE-REQUESTS)
  22      0   0.0  50000 100.0  49992 100.0        -  SWANK/SBCL::CALL-WITH-BREAK-HOOK
  23      0   0.0  50000 100.0  49992 100.0        -  (FLET SWANK/BACKEND:CALL-WITH-DEBUGGER-HOOK :IN "/Users/jcs/quicklisp/dists/quicklisp/software/slime-v2.22/swank/sbcl.lisp")
  24      0   0.0  50000 100.0  49992 100.0        -  SWANK::CALL-WITH-BINDINGS
  25      0   0.0  50000 100.0  49992 100.0        -  SWANK::HANDLE-REQUESTS
  26      0   0.0  50000 100.0  49992 100.0        -  (FLET SB-UNIX::BODY :IN SB-THREAD::NEW-LISP-THREAD-TRAMPOLINE)
  27      0   0.0  50000 100.0  49992 100.0        -  (FLET "WITHOUT-INTERRUPTS-BODY-4" :IN SB-THREAD::NEW-LISP-THREAD-TRAMPOLINE)
  28      0   0.0  50000 100.0  49992 100.0        -  (FLET SB-THREAD::WITH-MUTEX-THUNK :IN SB-THREAD::NEW-LISP-THREAD-TRAMPOLINE)
  29      0   0.0  50000 100.0  49992 100.0        -  (FLET "WITHOUT-INTERRUPTS-BODY-1" :IN SB-THREAD::CALL-WITH-MUTEX)
  30      0   0.0  50000 100.0  49992 100.0        -  SB-THREAD::CALL-WITH-MUTEX
  31      0   0.0  50000 100.0  49992 100.0        -  SB-THREAD::NEW-LISP-THREAD-TRAMPOLINE
  32      0   0.0  50000 100.0  49992 100.0        -  "foreign function call_into_lisp"
  33      0   0.0  50000 100.0  49992 100.0        -  "foreign function new_thread_trampoline"
  34      0   0.0    649   1.3  49992 100.0        -  "foreign function signal_emulation_wrapper"
  35      0   0.0      3   0.0  49992 100.0        -  "foreign function maybe_gc"
  36      0   0.0      3   0.0  49992 100.0        -  "foreign function interrupt_handle_pending"
------------------------------------------------------------------------
          8   0.0                                     elsewhere
#<CALL-GRAPH 50000 samples {1017C52A13}>

You can consult Section 16.2 of the SBCL manual for the details but what the profiling report says is that 99.9% of the time was spent in subseq and most of that was spent copying data.

The take away from all of this is that if you’re using Lisp and a frequently called function needs to take a substring, you might want to avoid subseq if you can. The other takeaway is that Guile’s implementation of substring with its copy-on-modify semantics is a real win.

-1:-- A Palindrome Predicate Coda (Post jcs)--L0--C0--January 07, 2020 04:42 PM

Sacha Chua: 2020-01-06 Emacs news

Links from reddit.com/r/emacs, r/orgmode, r/spacemacs, r/planetemacs, Hacker News, planet.emacslife.com, YouTube, the Emacs NEWS file and emacs-devel.

-1:-- 2020-01-06 Emacs news (Post Sacha Chua)--L0--C0--January 06, 2020 07:33 PM

Irreal: SBCL 2.0.0

Steel Bank Common Lisp has a new version out. I haven’t been writing much Common Lisp lately so I haven’t kept the software up to date. SBCL makes a new release every month and I always compile from source so it takes a tiny bit of effort to stay on the bleeding edge. Despite their aggressive release schedule, SBCL is very slow to make major releases so when I saw that they’d released SBCL 2.0.0, I knew it was time to upgrade. There’s been a bunch of optimizations, enhancements, and bug fixes so be sure to follow the link to see what’s new.

As usual, the compilation and exhaustive tests ran without any problems. I fired up a Slime session and played around with it a bit. I’d forgotten what a pleasurable experience SBCL/Slime/Emacs can be. You do everything from the comfort of Emacs but still have the power of an industrial strength Lisp environment at your fingertips. If you’re already an Emacser and would like to try out Common Lisp, this combination is ideal: it’s all free—as in beer and freedom—and easy to install. You can even get SBCL binaries if you don’t want to compile your own but except for Linux and Windows, the binaries are usually a few (monthly) releases behind so it pays to compile your own if you’re on a Mac or Unix system.

-1:-- SBCL 2.0.0 (Post jcs)--L0--C0--January 06, 2020 04:57 PM

Marcin Borkowski: Org agenda statistics, part I

Some time ago I wrote about the org-batch-agenda macro. I decided to finally put it in good use. My goal is to write a command-line tool (or alternatively, an Emacs command) displaying some statistics about my pending tasks. However, for that I needed to solve two (minor) problems.
-1:-- Org agenda statistics, part I (Post)--L0--C0--January 06, 2020 09:08 AM

Toby 'qubit' Cubitt: Lost or corrupted undo-tree history

Undo-tree is the most popular of the Emacs packages I wrote and maintain,not least because it's used by Evil and Spacemacs. However, for many years, the internet has been awashwith reports of undo history being lost or corrupted when using undo-tree-mode. Trouble was, though I do all my text editing in Emacs, and always have global-undo-tree-mode enabled, I'd never encountered these issues myself. And no one had ever been able to send me a recipe for reliably reproducing them. Making it fiendishly difficult to even begin to investigate what might be going on.

This post is about some recent changes to undo-tree that might finally address these issues.

-1:-- Lost or corrupted undo-tree history (Post Toby Cubitt (tsc25@cantab.net))--L0--C0--January 06, 2020 12:00 AM

Irreal: Adding System Notifications to Your Org Agenda

If you’re a Unix/Linux/MacOS user, chances are you have one or more cron jobs set up to handle routine maintenance chores. Cron jobs are an extraordinarily useful tool to make a lot of busy work disappear. Still, sometimes things go wrong and you’d like to know about it. That’s easy to do too. You can simply have your script output a notification of any anomalous conditions and cron will mail the notification to you.

The problem is that cron mails the notifications to your local machine mail account, which virtually nobody checks. You can, as Karl Voit used to do, set yourself a reminder to check it once a week or month or whatever time frame makes sense for you but that just leads to more busy work and problems may sit unnoticed between your scheduled checks.

Voit finally got tired of checking the machine mail account on each of his machines and set up a general mechanism to add cron job exception reports to his Org mode agenda. That turned out to be pretty easy to do. Voit doesn’t like programming in Elisp so he wrote some python scripts to append Org entries to his errors.org file. The cron job scripts call the python script to add errors and appropriate information to error.org which then gets displayed in his agenda. Follow the link to Voit’s post for the details including a few of the actual scripts he uses. It’s a very nice system and removes the need to periodically check for problems.

Of course, if you like Elisp, it would be easy to replace the Python with some Elisp, perhaps calling it from a script as Karlicoss showed us. In either case, take a look at Voit’s post. It’s full of good ideas for handling the routine but boring details of administering your own machine.

-1:-- Adding System Notifications to Your Org Agenda (Post jcs)--L0--C0--January 04, 2020 04:39 PM

Irreal: Why (or Why Not) Switch to Emacs

Protesilaos Stavrou has a very nice, detailed video that addresses the question of switching to Emacs. His approach to Emacs is, it seems to me, the correct one. He starts by stating—emphatically—that Emacs is not an editor; it’s a Lisp interpreter. That means you can make it do whatever you want: email, RSS, calendar, music, even text editing if you want.

His second point is little appreciated and much more controversial: the default Emacs keys are not that crazy. It’s not an easy case to make, especially when compared to Vim. While Vim has a logical set of composable commands that are easy to learn, Emacs’ key sequences seem random but are mnemonic once you learn the design principals. Still, Stavrou makes a reasonable case. They’re definitely not as easy or logical as Vim’s but they do have a certain tractive logic.

The most unusual part of Stavrou’s presentation is his list of reasons why you might not want to change to Emacs. It won’t, he says, make you cool or give you social acceptance. At the end of the day, no one cares whether or not you use Emacs. Not your employers and not your colleagues. In particular he says that if your current work flow is working for you, there’s no reason at all to switch to Emacs.

His final point is that Emacs requires commitment. You can’t be an “Emacs tourist.” Mastering it will take effort and won’t happen over the weekend. I see this realization a lot from people who have tried several times to adopt Emacs but couldn’t make it stick. It was only when they fully committed using Emacs all the time that they got over the initial hump and made Emacs their own.

The video is an hour long so you’ll definitely need to schedule time but I found it enjoyable and worth the time.

-1:-- Why (or Why Not) Switch to Emacs (Post jcs)--L0--C0--January 01, 2020 05:03 PM

Nicolas Martyanoff: Local CLHS access in Emacs

The CLHS, or Common Lisp HyperSpec, is one of the most important resource for any Common Lisp developer. It is derived from the official Common Lisp standard, and contains documentation for every aspect of the language.

While it is currently made available online by LispWorks, it can be useful to be able to access it locally, for example when you do not have any internet connection available.

For this purpose, LispWorks provides an archive which can be downloaded and browsed offline.

While the HyperSpec is valuable on its own, the SLIME Emacs mode provides various functions to make it even more useful.

I have found the following functions particularily useful:

  • slime-documentation-lookup, or C-c C-d h to browse the documentation associated with a symbol.
  • common-lisp-hyperspec-format, or C-c C-d ~, to lookup format control characters.
  • common-lisp-hyperspec-glossary-term, or C-c C-d g, to access terms in the glossary.

With the default configuration, Emacs will use the online HyperSpec. You can have it use a local copy by setting common-lisp-hyperspec-root to a file URI. For example, if you downloaded the content of the CLHS archive to ~/common-lisp/:

(setq common-lisp-hyperspec-root
  (concat "file://" (expand-file-name "~/common-lisp/HyperSpec/")))

And if you configure Emacs to use the EWW web browser, you can work with the CLHS without leaving your editor.

-1:-- Local CLHS access in Emacs (Post)--L0--C0--January 01, 2020 12:00 AM

Manuel Uberti: Helmify some completion mechanisms

Last year I wrote about making Company completion popup appear on demand. There I also briefly mentioned dabbrev-expand and dabbrev-completion, but I have never mentioned hippie-expand, and that it has been pretty much covering my completion needs.

However, moving to Helm prompted me to give helm-dabbrev a try. helm-dabbrev works similarly to dabbrev-completion, but when you hit helm-dabbrev-cycle-threshold (which defaults to 5), it takes you to a Helm buffer with all the benefits that come with it.

Two settings are necessary to have helm-dabbrev behave like I want to. First, I turned off Helm’s show completion, a feature which displays candidates in the current buffer. I don’t like popups, as you may have noticed, and I prefer Helm to always show candidates in the same position of the screen.

(setq helm-turn-on-show-completion nil)

Then, I made helm-dabbrev look for completions in all the available buffers.

(setq helm-dabbrev-related-buffer-fn nil)

By default, helm-dabbrev scans buffers with the same major mode as the current one, but this doesn’t help when, for instance, I am writing a commit message and I want a symbol to be completed. Binding helm-dabbrev to C-. is all that’s left to do.

Moreover, Helm improves on Company too. With the help of helm-company1 is possible to narrow down the candidates through Helm smart UI. C-TAB is my go-to key binding for helm-company.

Since Helm has become a great companion during my Emacs sessions, it makes sense to rely on it for everything concerning completion.

Footnotes

  1. I used to maintain helm-company before discovering Ivy, and now I’m back to it. The Emacs world is full of surprises. 

-1:-- Helmify some completion mechanisms (Post)--L0--C0--January 01, 2020 12:00 AM

Irreal: Emacs for Writers

Jacob Moena has a long post on using Emacs for creative writing. He begins by explaining why anyone would want to do such a thing. Of course, Emacsers already know the answer: Emacs will make you more productive, especially if you are a touch typist.

The majority of his post is a “whirlwind tour” tour of Emacs. It’s a fairly detailed tutorial on the editor’s features that a creative writer is apt to find useful. He also covers some of the packages that he uses in his own writing, including, of course, Org mode. He notes that it’s most useful to think of Emacs as an editor construction kit—although he doesn’t use those terms—and that this is its great strength: you can make Emacs adapt to your way of working instead of having to adapt your way of working to your editor.

His most important takeaway, I think, is

“The secret about Emacs is that it is driven by muscle memory, just like a musical instrument. It takes some time to get there, but once you do, you can operate it instinctively.”

If you’re an experienced Emacs user, you’ll probably find the whirlwind tour boring since it covers material you’re already familiar with. Still, he does cover some specialized commands that you may not know about so it’s worth at least skimming over it. If you’re an Emacs n00b and interested in seeing if Emacs is a good fit for your writing, Moena’s post will help you get started and tell you what to expect. There are a few typos (usually involving command shortcuts) that may be confusing so if you see something that doesn’t appear to make sense, it’s probably just a typo.

-1:-- Emacs for Writers (Post jcs)--L0--C0--December 31, 2019 05:40 PM

Flickr tag 'emacs': 2019-12-30 Emacs news

noushi46 posted a photo:

2019-12-30 Emacs news

ift.tt/2ZBhRSe

-1:-- 2019-12-30 Emacs news (Post noushi46 (nobody@flickr.com))--L0--C0--December 31, 2019 04:56 AM

Sacha Chua: 2019-12-30 Emacs news

Links from reddit.com/r/emacs, r/orgmode, r/spacemacs, r/planetemacs, Hacker News, planet.emacslife.com, YouTube, the Emacs NEWS file and emacs-devel.

-1:-- 2019-12-30 Emacs news (Post Sacha Chua)--L0--C0--December 30, 2019 01:07 PM

Irreal: Query Replace with Occur

Over at (with-Emacs, Clemens Radermacher has posted a short tutorial on using occur and query-replace across several files. It’s sort of a riff on abo-abo’s post on refactoring multiple files. To a first order approximation, the idea is to use occur to locate the term of interest, put the occur buffer in edit mode, and then use query-replace or your favorite replacement tool to make the actual substitutions.

This works fine if you’re interested in a single buffer but if the text of interest is spread across several buffers, you need to use multi-occur. I can’t ever remember doing this because multi-occur is hard to use. You have to specify each buffer you’re interested in and while you can make this a little easier with multi-occur-in-matching-buffers, it isn’t ideal either.

For me, the most interesting thing about Radermacher’s post is his recommendation to use Nicolas Petton’s noccur. It’s just like occur—actually, it’s a front end to the multi-occur command—but you can ask it to operate on all files in a project or all the files marked in a dired buffer. Noccur will load the requested files into buffers and call multi-occur.

There are plenty of other ways of doing this but Radermacher’s solution works in a seamless way for project files and dired-marked files. It’s definitely worth knowing the technique. Radermacher offers some code snippets to provide a bit of context for your replacement decisions and to solve a couple of other problems. It’s a good post and definitely worth taking the time to read.

-1:-- Query Replace with Occur (Post jcs)--L0--C0--December 28, 2019 04:09 PM

Irreal: Org Mode 9.3.1

Batien writes that he’s released Org 9.3.1. It’s a bug fix so you should probably update if you’re having any problems with Org 9.3. I updated yesterday and haven’t had any problems. Of course, that’s a study of \(n=1\) so you may see different results.

Thanks to Bastien, Nicolas, and all the others for the hard work they do to bring us this essential package and for keeping the development robust and active.

-1:-- Org Mode 9.3.1 (Post jcs)--L0--C0--December 27, 2019 04:43 PM

(with-emacs: Using Occur for Search and Replace across Files

This post describes how to combine occur with query-replace to search and replace across files and contains some useful Elisp snippets and recommendations to improve this workflow.

This post is a follow up of the more general post about search and replacement techniques in Emacs.

Search and replace in projects

To search with occur across files in projects I recommend the great noccur package. It’s a small package that provides some convenient commands which simplify using the built-in multi-occur for projects and from dired.

Show context on replace

After a search via M-x noccur-project or multi-occur or any other occur variant, you get an occur buffer with results grouped by files the matches where found in. In occur you can enter occur-edit-mode with e which makes the search results editable.

After you entered occur-edit-mode you can use query-replace or any editing commands you like to edit the search results. I prefer to see some context before replacing a match which can be done by setting up some hooks:

(add-hook 'occur-mode-hook
          (defun occur-show-replace-context+ ()
            (add-hook 'replace-update-post-hook
                      'occur-mode-display-occurrence nil 'local)))

The above adds occur-mode-display-occurrence to replace-update-post-hook in occur buffers, this way you always see the context when you are queried for the replace.

One problem is that occur-mode-display-occurrence messes with the match data (Emacs 26.3) which breaks query-replace. To fix this you need to use the following advice:

(define-advice occur-mode-display-occurrence
    (:around (fun &rest args) save-match-data)
  (save-match-data
    (apply fun args)))

Skip occur title lines for search and replace

By default query-replace and isearch won’t skip the header lines which show match info and therefore shouldn’t be included. To fix this you can use the following snippet:

(add-hook 'occur-mode-hook
          (defun isearch-occur-setup+ ()
            (add-function :after-while (local 'isearch-filter-predicate)
              'occur-isearch-filter-p+)))

(defun occur-isearch-filter-p+ (beg end)
  "Return non-nil if match should be considered."
  (and
   (save-excursion
     ;; always omit first line wich contains summary info and in multi-occur it
     ;; has no occur-title property and isn't read only
     (goto-char beg)
     (not (= (point-min) (line-beginning-position))))
   ;; omit the other occur header lines
   (not (or (get-text-property beg 'occur-title)
            (get-text-property end 'occur-title)))))

The above adds a local filter predicate for occur which takes care of omitting the header lines for search and replace operations. To learn more about how this works you can find more info in the docstrings of add-function and isearch-filter-predicate.

You could also set the variable isearch-filter-predicate buffer locally using setq-local but using add-function like shown above has the benefit of automatically respecting other filter predicates you might have setup.

Auto-save edits

After you are done with your edits you can get back to regular occur-mode with C-c C-c. The modified buffers are not automatically saved to disk but if you would like to do that you can use the following:

(defvar-local occur-edit-buffers+ nil
  "Save buffers in which occur performed changes.")

(add-hook 'occur-edit-mode-hook
          (defun occur-eddit-save-edits+ ()
            (add-hook 'after-change-functions
                      'occur-edit-remember-buffer+ nil t)))

(defun occur-edit-remember-buffer+ (&rest _)
  (let* ((m (get-text-property (line-beginning-position) 'occur-target))
         (buf (and (markerp m) (marker-buffer m))))
    (when buf
      (pushnew buf occur-edit-buffers+))))

(define-advice occur-cease-edit (:before () save-edits)
  (dolist (buf occur-edit-buffers+)
    (with-current-buffer buf
      (save-buffer))))
-1:-- Using Occur for Search and Replace across Files (Post clemera)--L0--C0--December 27, 2019 02:00 PM

Irreal: Implementing Palindrome Predicates

Joe Marshall is a long-time Lisper with an ability to come up with really elegant solutions. Indeed, the second ever Irreal post was about Marshall’s brilliant solution to a problem from SICP. Recently, he recounted a story about a recent phone screen he had in which he was asked to implement a palindrome detector. He wrote both an iterative and a recursive version. He says he gave them the iterative version so they wouldn’t think him an idiot but that he liked the recursive version better because of its simplicity and elegance.

If you think of a palindrome detector as embodying the three rules

  1. The empty string is a palindrome
  2. A string with a single character is a palindrome
  3. If the first and last characters of a string are identical and the substring between them is a palindrome, then the original string is a palindrome

the recursive algorithm writes itself.

Marshall doesn’t show his code so of course I had to try it myself. My initial effort was to bang out an Elisp implementation:

(defun palindromep (string)
(let ((len (length string)))
  (cond
   ((zerop len) t)
   ((= 1 len) t)
   ((not (char-equal (aref string 0) (aref string (1- len)))) nil)
   (t (palindromep (substring string 1 -1))))))

That’s practically a word-for-word rendition of the three rules and it worked well. But then I started thinking that Marshall said the iterative solution would be faster for most compilers. I don’t know what language he used but it almost certainly wasn’t Lisp so I wondered if the iterative version would be faster in a Lisp language. Of course I had to write an iterative version so I could compare them.

My first inclination was to write the iterative version in Elisp too but Elisp isn’t tail recursive so it would be hard to run the recursive version on large inputs. Therefore I decided to start over with Scheme. The recursive version is the same, mutatis mutandis, as the Elisp version.

(define palindrome-r?
  (lambda (string)
    (let ((len (string-length string)))
      (cond
       ((zero? len) #t)
       ((= 1 len) #t)
       ((not (char=? (string-ref string 0) (string-ref string (1- len)))) #f)
       (#t (palindrome-r? (substring string 1 (1- len))))))))

The iterative version is a little more complicated—mostly because of the do loop—but doesn’t seem nearly as elegant as the recursive version.

(define palindrome-i?
  (lambda (string)
    (do ((h 0 (1+ h))
         (t (1- (string-length string)) (1- t))
         (palindrome? #t))
        ((or (not palindrome?) (> h t))
         palindrome?)
      (set! palindrome? (char=? (string-ref string h) (string-ref string t))))))

The real test, though, is their relative speeds. In Scheme with its tail recursion, loops are generally implemented as recursion and you wouldn’t expect much difference. I ran the comparison in Guile Scheme, which has copy-on-modify string behavior so, again, the two versions seem like they should run in about the same time.

Of course, the results were nothing like that. I ran each version 1000 times on a large palindrome (100,000 x’s) with the following

(define str (make-string 100000 #\x))

(define bench
  (lambda (rcnt f)
    (do ((i rcnt (1- i)))
        ((zero? i))
      (f str))))

and here are the results

,time (bench 1000 palindrome-r?)
;; 9.204000s real time, 9.370000s run time.  2.330000s spent in GC.
,time (bench 1000 palindrome-i?)
;; 4.582000s real time, 4.660000s run time.  1.350000s spent in GC.

The recursive version runs almost exactly twice as long so Marshall was correct even in the Lisp case.

None of this is very important, of course, but it was an interesting exercise that reinforced the lesson that it’s really hard to predict run times without benchmarking.

-1:-- Implementing Palindrome Predicates (Post jcs)--L0--C0--December 26, 2019 04:11 PM

Alex Ott: New version of article about Emacs/CEDET

I just uploaded to site the new version of my article A Gentle introduction to CEDET. I also left old version of this article, but as separate page.
New version describes CEDET with new activation scheme, so it's now applicable to versions from bzr, and to versions bundled with GNU Emacs (after they will release next GNU Emacs version, where CEDET was updated).
Besides this, I added small description of how to customize CEDET to work with Java, and small section about setting name completion through the auto-complete package.

Instead of my config file, that contains too much not necessary stuff, now it's better to use separate config.

P.S. btw, fresh snapshots of CEDET can automatically detect Maven projects, and get classpath information directly from them. So now, names completion works also for 3rd party libraries. For example, this is name completion during work with source code from Apache Tika:
-1:-- New version of article about Emacs/CEDET (Post Alex Ott (noreply@blogger.com))--L0--C0--December 26, 2019 02:06 PM

Irreal: Emacs Screencasts

Over at Meta Redux, Bozhidar Batsov, who will need no introduction to Emacs users, has a nice post on how to make a screencast from within Emacs. The result is actually an animated GIF but the results in his demo video look very good. The nice thing about his method is that it takes a screen capture only when you do something so the resulting files are smaller and there are no pauses when you’re not doing something.

The screencasts are made with the emacs-gif-screencast package that’s available on Melpa. You’ll need a couple of extra packages as well: Imagemagick and Gifsicle both of which are available on HomeBrew for MacOS users and are probably already installed on Linux—if not prebuilt binaries or source are available at the above links.

There are a few weaknesses, which Batsov discusses but nothing serious and he concludes that it’s a “pretty cool tool” so if you’re looking for any easy way to make a screencast from within Emacs you should definitely give it a look. You won’t be able to make the type of video that, say, Mike Zamansky produces but if you need a quick screencast to demo some process, emacs-gif-screencast is ideal.

-1:-- Emacs Screencasts (Post jcs)--L0--C0--December 25, 2019 04:45 PM

Emacs Redux: Adding a Bit of Holiday Spirit to Emacs

Christmas is here! Is your Emacs ready for it?

Emacs is famous for having a major mode for any and every occasion, but does this hold true for Christmas? I was shocked to find out this morning that there’s no christmas-mode or christmas-tree-mode! Still, I did manage to figure out a way to optimize my Emacs for the holiday season, at least for the people living in countries where the holidays happen to be during the winter.

If you’re feeling cold and you need some extra warmth in your life Emacs can certainly help with that! Enter emacs-fireplace. It’s a major mode that turns your Emacs into… a cozy fireplace.

emacs-fireplace.gif

So, just enable the mode with M-x fireplace and bask in the warmth and glory of Emacs. Using the mode is super simple (consider pressing C-* to enable smoke) and I guess you’ll be able to figure out the details by yourselves.

Merry Christmas! Merry Mxmas! Until next time!

-1:-- Adding a Bit of Holiday Spirit to Emacs (Post Bozhidar Batsov)--L0--C0--December 25, 2019 07:47 AM

Irreal: Emacs 27 Release Branch

Eli Zaretskii writes on the Emacs Development list that he’s created the Emacs 27 release branch. Next up is the Emacs 27.1 pretest, which he hopes to release soon. He’s also set the version number of Emacs on the Master branch to 28.0.50.

Emacs 27 is finally in sight. In the meantime, we can start obsessing about Emacs 28. If you haven’t already, take a look at John Wiegley’s video on what’s coming in Emacs 27.

-1:-- Emacs 27 Release Branch (Post jcs)--L0--C0--December 24, 2019 04:43 PM

Sacha Chua: 2019-12-23 Emacs news

Links from reddit.com/r/emacs, r/orgmode, r/spacemacs, r/planetemacs, Hacker News, planet.emacslife.com, YouTube, the Emacs NEWS file and emacs-devel.

-1:-- 2019-12-23 Emacs news (Post Sacha Chua)--L0--C0--December 24, 2019 11:12 AM

Irreal: Plain Text For the Social Sciences

Regular readers know that I’m fascinated by the ways that non-technical folks make use of Emacs. Despite our prejudiced assumptions, they are often sophisticated and subtle in the ways they leverage Emacs. Recently, Eric Fraga tweeted a pointer to a long article by Kieran Healy on using plain text and Emacs for writing in the social sciences.

The article is mainly addressed to the beginning graduate school student and makes the case that if you are going to do any quantitative work in your research then you’re better off using plain text and a text editor rather than a word processor for writing your papers and books. Most Irreal readers won’t find this the slightest bit controversial and will need no convincing but social scientists are different. Their culture and training has led them to believe that writing papers is something done with Word. Their professional journals agree. With that in mind, it’s easy to see why Haley’s position can be a hard sell.

Healy is mostly concerned with workflow and although he is an Emacs user, he doesn’t insist that it’s the only good solution. He suggests several alternatives but does note that Emacs is a powerful tool that can make writing easier. He assumes that “quantitative” means “statistical” and that his readers will be using R. His workflow involves writing in Markdown and using knitr to evaluate the R code blocks and insert the results in much the same way that Org and Babel work. Org and Babel would provide a more seamless and slightly easier solution so I’m not sure why he doesn’t use them. Healy is a Full Professor at Duke so Org probably wasn’t available when he started and he’s just stuck with his “good enough” solution. The article discusses his entire tool chain with particular attention to revision control and backups so it’s about more than just what editor and markup language to use.

As I said, the article is long—a PDF version runs to 49 pages (although with generous margins)—but it’s interesting and makes many good points even if you don’t agree with all his choices of tools. I recommend reading the PDF version because it has the footnotes and is a single document rather than a series of pages.

-1:-- Plain Text For the Social Sciences (Post jcs)--L0--C0--December 23, 2019 04:37 PM

Marcin Borkowski: Counting sentences in emails

Some time ago I wrote about sentence counting in Emacs buffers (or regions). I promised a sequel, and here it is. The real reason to count sentences is that I wanted to be able to automatically put a signature in my email referring to one of the http://sentenc.es/ webpages. It turns out, however, that counting sentences in email messages is much more difficult than it seems.
-1:-- Counting sentences in emails (Post)--L0--C0--December 23, 2019 03:01 PM

Manuel Uberti: Developing Helm actions

One of the central pieces of my recent return to Helm is helm-ls-git, which empowers helm-browse-project with everything I need to move through my Git projects smoothly. Combine that with helm-projects-history, and you can see why I don’t need Projectile any more. Well, sort of. It’s true that I’ve stopped using Projectile since Helm took over my Emacs configuration, but it’s also true that I had to code the “helmified” version of a couple of features I was heavily relying upon.

In Helm, you can leverage actions to extend the available utilities.

(defun mu--candidate-directory (candidate)
  "Find the project root or the directory containing CANDIDATE.
Default to `default-directory' when none can be found, or to
`helm-current-directory' when CANDIDATE is not in a project."
  (if (fboundp 'helm-ls-git-root-dir)
      (let ((dir (cond ((stringp candidate)
                        (file-name-directory candidate))
                       ((and (bufferp candidate)
                             (buffer-file-name candidate))
                        (file-name-directory (buffer-file-name candidate)))
                       (t default-directory))))
        (helm-ls-git-root-dir dir))
    (helm-current-directory)))

(defun mu-helm-project-dired ()
  "Open Dired buffers at project root from a Helm session."
  (interactive)
  (dolist (cand (helm-marked-candidates))
    (dired (mu--candidate-directory cand))))

(defun mu-helm-project-shell ()
  "Open shell buffers at project root from a Helm session."
  (interactive)
  (dolist (cand (helm-marked-candidates))
    (let* ((default-directory (mu--candidate-directory cand))
           (buffer (concat "*shell "
                           (file-name-nondirectory
                            (directory-file-name default-directory))
                           "*")))
      (mu-shell-open buffer))))

The actions are self-explanatory (see Passing the prefix argument around for mu-shell-open). I often need to jump to a Dired or a shell-mode buffer of a project different from the current one, so I want the possibility to use the current candidate in helm-projects-history as a starting point.

To be fair, mu--candidate-directory does a little more than what I need here. That’s because I use mu-helm-project-dired and mu-helm-project-shell in helm-buffers-list and helm-browse-project too. The latter lists special buffers (e.g., *scratch*) as buffers of the current project. Since they do not live in any specific directory, default-directory is the obvious choice.

Now I have to plug the actions into helm-projects-history. Unfortunately, it doesn’t have a keymap to extend, so I need another solution.

(defvar mu-helm-projects-history-map
  (let ((map (make-sparse-keymap)))
    (set-keymap-parent map helm-map)
    (define-key map (kbd "C-c d") (helm-exit-and-run! (mu-helm-project-dired)))
    (define-key map (kbd "C-c s") (helm-exit-and-run! (mu-helm-project-shell)))
    map)
  "Keymap for `mu-helm-projects-history'.")

(defun mu-helm-projects-history (arg)
  "A `helm-projects-history' with custom actions."
  (interactive "P")
  (require 'helm-ls-git)
  (helm :sources
        (helm-build-sync-source "Project history"
          :candidates helm-browse-project-history
          :action (lambda (candidate)
                    (with-helm-default-directory candidate
                      (helm-browse-project
                       (or arg helm-current-prefix-arg))))
          :keymap mu-helm-projects-history-map)
        :buffer "*helm browse project history*"))

mu-helm-projects-history adds only two things to the original helm-projects-history. I require helm-ls-git early because I need its capabilities inside my actions, and I use my own mu-helm-projects-history-map to make them available in the Helm buffer opened by this command.

Last but not least, helm-exit-and-run! is a helpful macro to avoid dry repetitions:

(defmacro helm-exit-and-run! (&rest body)
  "Define an action with BODY to run after exiting Helm."
  (declare (doc-string 1))
  `(lambda ()
     (interactive)
     (with-helm-alive-p
       (helm-exit-and-execute-action (lambda (_candidate) ,@body)))))

Note that in my actions I am ignoring the _candidate parameter on purpose. Since helm-marked-candidates grabs the current candidate when none of them is selected, I can use my actions on multiple candidates if I feel wild enough. Yeah, sometimes I can be crazy like that.

-1:-- Developing Helm actions (Post)--L0--C0--December 23, 2019 12:00 AM

Irreal: John Wiegley on Emacs 27

In another of the videos from Emacs Conference 2019, John Wiegley talks about what’s coming in Emacs 27. Wiegley is still the official maintainer but Eli Zaretskii stepped up to do the heavy lifting when Wiegley’s job intervened. Wiegley says that Zaretskii is now the de facto maintainer but that he was not available to give the talk so Wiegley made the presentation.

There are several interesting changes coming. Lispers will be happy to learn that Elisp will finally be getting BIGINT support. It still doesn’t have a full numerical tower but BIGINT support is probably the most important missing piece.

On the display side, Emacs 27 is getting support for Harfbuzz, Cairo, and better ligature support. Another display-like feature is support for tabs. This is not just tabs in the browser sense—because who needs that in Emacs—but a mechanism for maintaining window configurations and switching between them.

Some other interesting enhancements are the portable dumper (a long time coming but we’re finally free of depending on glibc hacks to build our core image), initial support for the XDG directory configuration standard, so-long-mode to help deal with very long lines slowing down Emacs, and gettext integration to support internationalization of error messages and the like.

You can get more details by watching Wiegley’s talk but, unfortunately, the audio dropped out several times during his presentation. Still, every serious Emacser will want to watch the video to see what’s coming in Emacs 27.

-1:-- John Wiegley on Emacs 27 (Post jcs)--L0--C0--December 22, 2019 04:37 PM

Irreal: Emacs As Your Shell

I’m finally finding time to watch more of the videos from the Emacs Conference 2019. Howard Abrams gave an interesting talk on using Emacs as his shell and scripting language. As he says, it’s just him trying out some ideas meant for his personal use.

He starts out with a typical shell pipeline and wonders how the same thing might be done in Emacs. Why would you want to do that? The problem is that a pipeline’s intermediate results are pretty much opaque. You see the input and you see the output but not what’s happening in the middle. By using Emacs, you can see what the data looks like at every step. Abrams also says that in general Emacs tools are superior to the shell so you gain there too. It turns out not to be very difficult to use Emacs interactively to do a task that you might otherwise use a pipeline for. Abrams demonstrates this by using Emacs to do the same thing as his original pipeline.

In the second half of the talk, Abrams considers how you might use Elisp as a scripting language. He puts together some macros and functions that lets him write vaguely shell-like scripts but within Emacs. The advantage to this approach is that he has the full power of Emacs available whenever he needs it.

I can imagine circumstances where I might use Emacs interactively instead of a pipeline but I don’t think I’d bother with the scripting. I’m happy to use a shell script if that’s what the job requires. Still, Abrams’ approach was interesting and definitely worth taking a look at. You might even decided to adopt his approach.

Sadly, there were technical problems and the video feed was lost in the middle of the talk. That’s not as serious as it could have been because it happened near the end of the talk proper and mostly affected the Q&A. Secondly, Abrams has provided a sort of transcript of the talk complete with the slides. That makes it pretty easy to follow along in the part without video. As usual with Abrams’ videos, you’ll probably learns some new things and it is definitely worth your while.

-1:-- Emacs As Your Shell (Post jcs)--L0--C0--December 20, 2019 06:09 PM

emacspeak: Speaking Of Chess: Speech-Enabling Emacs Chess In Emacspeak

Speaking Of Chess: Speech-Enabling Emacs Chess In Emacspeak

1 Overview

1.1 Research question:

What type of spoken feedback does one need to:


  1. Learn Chess.
  2. Examine and learn from games.
  3. Play effectively.
  4. View the state of the game from different perspectives during a game.
  5. Provide auditory feedback that is both succinct and maximally informative.
  6. Arrive at a spoken notation for speaking various game states
    that is both expressive and time-efficient.


1.2 Speech-Enabling Chess In Emacspeak

To answer some or all of the above questions, I speech-enabled Emacs
Chess last weekend via module emacspeak-chess.el — see User Manual
for complete end-user documentation.


Module emacspeak-chess speech-enables Emacs Chess by:


  1. Providing interactive commands that let the user navigate and browse the
    chessboard along the eight compass directions from the current square.
  2. Spoken output uses audio-formatting — subtle changes in voice
    characteristics backed up by auditory icons — to indicate the
    color of squares and pieces.
  3. Speaking each current move as it happens.
  4. Adding the same spoken output to emacs chess commands for
    moving back and forth through a game.


In the above, all of the heavy lifting is done by three functions:




Share And Enjoy!


-1:-- Speaking Of Chess: Speech-Enabling Emacs Chess In Emacspeak (Post T. V. Raman (noreply@blogger.com))--L0--C0--December 18, 2019 05:30 PM

Marcin Borkowski: rot13 and other Caesar ciphers in Emacs

A few days ago I saw a friend’s message on the Internet. The message looked like a bunch of random characters. Of course, I suspected a simple substitution cipher. What do I do?
-1:-- rot13 and other Caesar ciphers in Emacs (Post)--L0--C0--December 16, 2019 09:56 PM

Sacha Chua: 2019-12-16 Emacs news

Links from reddit.com/r/emacs, r/orgmode, r/spacemacs, r/planetemacs, Hacker News, planet.emacslife.com, YouTube, the Emacs NEWS file and emacs-devel.

-1:-- 2019-12-16 Emacs news (Post Sacha Chua)--L0--C0--December 16, 2019 04:46 PM

Irreal: Displaying Org-mode Notifications Natively on MacOS

As many of you know, I live happily in the Apple Ecosystem but do virtually everything that doesn’t involve the browser in Emacs. One exception is my calendar. Events like “Renew ACM membership” or “Research ways of doing \(X\)” are added to my todo.org file and appear in my Org Agenda. Events with a specific, hard date and time attached, such as a doctors appointment, are added to my Apple calendar.

That’s a bit schizophrenic, of course, but it works well for me. The advantage of using the Calendar app is that the event and details about it are synched to my other Apple devices—including my iPhone—and so go with me everywhere. It’s possible, certainly, to use an app like beorg or organice to get my Org-mode events synched to my iPhone but as I said, this system works well for me.

A potential problem with maintaining one’s calendar in Org-mode is alerts. The Calendar app will alert you to upcoming events even when you’re not in Emacs. It wouldn’t do to miss an alert from Emacs because you happen to be, say, in the browser. Christian Tietze has in interesting post in which he explores the beginning of a solution to the problem of having Emacs generate MacOS native alerts. It turns out to be pretty easy although there are some edge cases. Those seem reasonably easy to fix so if you’re interested in that type of functionality, be sure to take a look at Tietze’s post.

There are other possibilities. One is to use Growl. It’s a notification system that can receive messages from other applications and show them on a system wide basis. There is, of course, an Emacs interface. Or two. Another possibility is John Wiegley’s alert module, which he describes as a Growl workalike. Doubtlessly these systems would require a bit of integration but since I’m satisfied with my hybrid solution, I haven’t looked into what would be involved.

-1:-- Displaying Org-mode Notifications Natively on MacOS (Post jcs)--L0--C0--December 14, 2019 04:41 PM

Alex Schroeder: Gnus IMAP issues

I’ve started using Gnus again in recent weeks and months. One problem I have is that I enter the INBOX group using C-u RET or issue / o inside the group to see all the mail in my INBOX, read and unread, but all I get are 17 mails. I know some are missing.

When I use the Server Buffer via ^ and enter the INBOX, I get 50 mails. This includes all the missing mails.

I sometimes suspect that it has to do with me reading mails on the phone, too.

Do you understand what’s going on? Many years ago I had decided that the Gnus Agent was a problem and disable it setting gnus-agent to nil. (My entire Gnus config is available online.)

I removed the newsrc files (.newsrc.eld, .newsrc-dribble, their backup files), started Gnus again, and all I seem to have lost was the read marks. As I had all groups “read” that wasn’t a problem, a quick “catch-up” on the groups in questions solved that; then I went into my INBOX and all the mails were there. Let’s see whether it degenerates again.

Tags:

-1:-- Gnus IMAP issues (Post)--L0--C0--December 14, 2019 03:30 PM