<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title>KHTDR – Emacs</title><description/><link>https://khtdr.com/tags/emacs.html</link><lastBuildDate>Thu, 17 Sep 2026 00:00:00 +0000</lastBuildDate><language>en-us</language><managingEditor>mazzarelli@gmail.com (Joey Mazzarelli)</managingEditor><webMaster>mazzarelli@gmail.com (Joey Mazzarelli)</webMaster><atom:link href="https://khtdr.com/tags/emacs/index.xml" rel="self" type="application/rss+xml"/><item><title>Creating a Custom Emacs Mode</title><description> Learn how to create an interactive Emacs mode that maintains state between sessions
Introduction In this tutorial, we'll create a custom major mode for Emacs that demonstrates how to:
Associate a new file extension with your mode Create an interactive buffer with buttons Maintain state between sessions Handle file serialization The Example: foo-mode We'll create a simple mode that:
Associates with .foo files Displays a clickable button Tracks how many times the button was clicked Saves the count when the buffer is saved Restores the count when the file is reopened Implementation Here's the complete implementation of our foo-mode:</description><link>https://khtdr.com/emacs-custom-mode-tutorial.html</link><guid>https://khtdr.com/emacs-custom-mode-tutorial.html</guid><pubDate>Thu, 17 Sep 2026 00:00:00 +0000</pubDate><author>mazzarelli@gmail.com (Joey Mazzarelli)</author><category>Tutorials</category><content:encoded>
&lt;![CDATA[
&lt;blockquote&gt;
&lt;p&gt;Learn how to create an interactive Emacs mode that maintains state between sessions&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div id="outline-container-headline-1" class="outline-2"&gt;
&lt;h2 id="headline-1"&gt;
Introduction
&lt;/h2&gt;
&lt;div id="outline-text-headline-1" class="outline-text-2"&gt;
&lt;p&gt;In this tutorial, we&amp;#39;ll create a custom major mode for Emacs that demonstrates how to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Associate a new file extension with your mode&lt;/li&gt;
&lt;li&gt;Create an interactive buffer with buttons&lt;/li&gt;
&lt;li&gt;Maintain state between sessions&lt;/li&gt;
&lt;li&gt;Handle file serialization&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-headline-2" class="outline-2"&gt;
&lt;h2 id="headline-2"&gt;
The Example: foo-mode
&lt;/h2&gt;
&lt;div id="outline-text-headline-2" class="outline-text-2"&gt;
&lt;p&gt;We&amp;#39;ll create a simple mode that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Associates with .foo files&lt;/li&gt;
&lt;li&gt;Displays a clickable button&lt;/li&gt;
&lt;li&gt;Tracks how many times the button was clicked&lt;/li&gt;
&lt;li&gt;Saves the count when the buffer is saved&lt;/li&gt;
&lt;li&gt;Restores the count when the file is reopened&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-headline-3" class="outline-2"&gt;
&lt;h2 id="headline-3"&gt;
Implementation
&lt;/h2&gt;
&lt;div id="outline-text-headline-3" class="outline-text-2"&gt;
&lt;p&gt;Here&amp;#39;s the complete implementation of our foo-mode:&lt;/p&gt;
&lt;div class="src src-emacs-lisp"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-emacs-lisp" data-lang="emacs-lisp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;;;; foo-mode.el --- A tiny stateful major mode -*- lexical-binding: t -*-&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;defvar&lt;/span&gt; &lt;span class="nv"&gt;foo-mode-map&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;let&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nv"&gt;map&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;make-sparse-keymap&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;define-key&lt;/span&gt; &lt;span class="nv"&gt;map&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;kbd&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;C-c C-c&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;#&amp;#39;&lt;/span&gt;&lt;span class="nv"&gt;foo-increment-count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;map&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s"&gt;&amp;#34;Keymap for &lt;/span&gt;&lt;span class="ss"&gt;`foo-mode&amp;#39;&lt;/span&gt;&lt;span class="s"&gt;.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;defvar-local&lt;/span&gt; &lt;span class="nv"&gt;foo-count&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s"&gt;&amp;#34;Number of clicks recorded in the current buffer.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;define-derived-mode&lt;/span&gt; &lt;span class="nv"&gt;foo-mode&lt;/span&gt; &lt;span class="nv"&gt;special-mode&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Foo&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s"&gt;&amp;#34;Major mode for .foo files with a clickable counter.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;The file on disk holds just the count as a number. The buffer
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;shows a rendered view of it, which is regenerated as needed.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;;; When the mode starts, the buffer contains the raw file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;;; contents. Parse the count out of them before redrawing.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;setq&lt;/span&gt; &lt;span class="nv"&gt;foo-count&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;string-to-number&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;buffer-string&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;;; Take over saving: we write the count, not the buffer text.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;add-hook&lt;/span&gt; &lt;span class="ss"&gt;&amp;#39;write-contents-functions&lt;/span&gt; &lt;span class="nf"&gt;#&amp;#39;&lt;/span&gt;&lt;span class="nv"&gt;foo-mode-save&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="no"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;foo-mode-refresh&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;set-buffer-modified-p&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;defun&lt;/span&gt; &lt;span class="nv"&gt;foo-mode-refresh&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s"&gt;&amp;#34;Redraw the buffer from &lt;/span&gt;&lt;span class="ss"&gt;`foo-count&amp;#39;&lt;/span&gt;&lt;span class="s"&gt;.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;let&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nv"&gt;inhibit-read-only&lt;/span&gt; &lt;span class="no"&gt;t&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;erase-buffer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;insert&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Count: %d
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt; &lt;span class="nv"&gt;foo-count&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;insert-button&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Click me!&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="ss"&gt;&amp;#39;action&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;lambda&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;_button&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;foo-increment-count&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="ss"&gt;&amp;#39;follow-link&lt;/span&gt; &lt;span class="no"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;goto-char&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;point-min&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;defun&lt;/span&gt; &lt;span class="nv"&gt;foo-increment-count&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s"&gt;&amp;#34;Increment the counter and refresh the display.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;interactive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;setq&lt;/span&gt; &lt;span class="nv"&gt;foo-count&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;1+&lt;/span&gt; &lt;span class="nv"&gt;foo-count&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;foo-mode-refresh&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;set-buffer-modified-p&lt;/span&gt; &lt;span class="no"&gt;t&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;defun&lt;/span&gt; &lt;span class="nv"&gt;foo-mode-save&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s"&gt;&amp;#34;Write &lt;/span&gt;&lt;span class="ss"&gt;`foo-count&amp;#39;&lt;/span&gt;&lt;span class="s"&gt; to the visited file.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;Returns non-nil so that Emacs does not also write the buffer text.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;write-region&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;number-to-string&lt;/span&gt; &lt;span class="nv"&gt;foo-count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="nf"&gt;buffer-file-name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;set-visited-file-modtime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;set-buffer-modified-p&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;message&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Saved count %d to %s&amp;#34;&lt;/span&gt; &lt;span class="nv"&gt;foo-count&lt;/span&gt; &lt;span class="nf"&gt;buffer-file-name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="no"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;add-to-list&lt;/span&gt; &lt;span class="ss"&gt;&amp;#39;auto-mode-alist&lt;/span&gt; &lt;span class="o"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;\\.foo\\&amp;#39;&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;foo-mode&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;provide&lt;/span&gt; &lt;span class="ss"&gt;&amp;#39;foo-mode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-headline-4" class="outline-2"&gt;
&lt;h2 id="headline-4"&gt;
Usage
&lt;/h2&gt;
&lt;div id="outline-text-headline-4" class="outline-text-2"&gt;
&lt;ol&gt;
&lt;li&gt;Save the code above to &lt;code class="verbatim"&gt;~/.emacs.d/lisp/foo-mode.el&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add to your Emacs init file:&lt;/p&gt;
&lt;div class="src src-emacs-lisp"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-emacs-lisp" data-lang="emacs-lisp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;add-to-list&lt;/span&gt; &lt;span class="ss"&gt;&amp;#39;load-path&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;~/.emacs.d/lisp&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="ss"&gt;&amp;#39;foo-mode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;Create a new file with the .foo extension&lt;/li&gt;
&lt;li&gt;The buffer will show a count and a clickable button&lt;/li&gt;
&lt;li&gt;Click the button or press &lt;code class="verbatim"&gt;C-c C-c&lt;/code&gt; to increment&lt;/li&gt;
&lt;li&gt;Save the file (&lt;code class="verbatim"&gt;C-x C-s&lt;/code&gt;) to persist the count&lt;/li&gt;
&lt;li&gt;Close and reopen to see the count restored&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-headline-5" class="outline-2"&gt;
&lt;h2 id="headline-5"&gt;
How It Works
&lt;/h2&gt;
&lt;div id="outline-text-headline-5" class="outline-text-2"&gt;
&lt;div id="outline-container-headline-6" class="outline-3"&gt;
&lt;h3 id="headline-6"&gt;
Mode Definition
&lt;/h3&gt;
&lt;div id="outline-text-headline-6" class="outline-text-3"&gt;
&lt;p&gt;The mode is defined using &lt;code class="verbatim"&gt;define-derived-mode&lt;/code&gt;, which creates a new major mode derived from &lt;code class="verbatim"&gt;special-mode&lt;/code&gt;. Deriving from &lt;code class="verbatim"&gt;special-mode&lt;/code&gt; gives us a read-only buffer out of the box, which is what we want for a buffer that is rendered rather than typed into. It also gives us the usual conveniences like &lt;code class="verbatim"&gt;q&lt;/code&gt; to quit the window.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-headline-7" class="outline-3"&gt;
&lt;h3 id="headline-7"&gt;
State Management
&lt;/h3&gt;
&lt;div id="outline-text-headline-7" class="outline-text-3"&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class="verbatim"&gt;foo-count&lt;/code&gt; is a buffer-local variable that stores the click count&lt;/li&gt;
&lt;li&gt;&lt;code class="verbatim"&gt;foo-mode-refresh&lt;/code&gt; erases the buffer and redraws it from &lt;code class="verbatim"&gt;foo-count&lt;/code&gt;. Because the buffer is read-only, we bind &lt;code class="verbatim"&gt;inhibit-read-only&lt;/code&gt; while doing so.&lt;/li&gt;
&lt;li&gt;&lt;code class="verbatim"&gt;foo-increment-count&lt;/code&gt; bumps the counter, redraws, and marks the buffer modified so that &lt;code class="verbatim"&gt;C-x C-s&lt;/code&gt; knows there is something to save&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-headline-8" class="outline-3"&gt;
&lt;h3 id="headline-8"&gt;
Loading
&lt;/h3&gt;
&lt;div id="outline-text-headline-8" class="outline-text-3"&gt;
&lt;p&gt;When Emacs opens a &lt;code class="verbatim"&gt;.foo&lt;/code&gt; file, it reads the file into the buffer and then activates the mode. So at the top of the mode body, the buffer contains the raw file contents: just a number. We parse it with &lt;code class="verbatim"&gt;string-to-number&lt;/code&gt; (an empty buffer, as with a brand new file, gives 0), then redraw and mark the buffer unmodified so Emacs does not immediately think you have unsaved changes.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-headline-9" class="outline-3"&gt;
&lt;h3 id="headline-9"&gt;
Saving
&lt;/h3&gt;
&lt;div id="outline-text-headline-9" class="outline-text-3"&gt;
&lt;p&gt;This is the interesting part. The buffer text is a rendered view, not the data, so we do not want Emacs to write it to disk. Instead we add &lt;code class="verbatim"&gt;foo-mode-save&lt;/code&gt; to &lt;code class="verbatim"&gt;write-contents-functions&lt;/code&gt;, buffer-locally. Emacs runs these functions when you save, and if one of them returns non-nil, Emacs considers the save handled and skips writing the buffer itself.&lt;/p&gt;
&lt;p&gt;
Inside &lt;code class="verbatim"&gt;foo-mode-save&lt;/code&gt; we write just the number with &lt;code class="verbatim"&gt;write-region&lt;/code&gt;, then call &lt;code class="verbatim"&gt;set-visited-file-modtime&lt;/code&gt; so Emacs knows the change on disk was ours (otherwise the next save would warn that the file changed on disk), and clear the modified flag.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-headline-10" class="outline-3"&gt;
&lt;h3 id="headline-10"&gt;
File Association
&lt;/h3&gt;
&lt;div id="outline-text-headline-10" class="outline-text-3"&gt;
&lt;p&gt;The mode automatically activates for &lt;code class="verbatim"&gt;.foo&lt;/code&gt; files through the &lt;code class="verbatim"&gt;auto-mode-alist&lt;/code&gt; addition.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-headline-11" class="outline-3"&gt;
&lt;h3 id="headline-11"&gt;
Interaction
&lt;/h3&gt;
&lt;div id="outline-text-headline-11" class="outline-text-3"&gt;
&lt;p&gt;The mode provides two ways to increment the counter:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Clicking the button (using &lt;code class="verbatim"&gt;insert-button&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Using the &lt;code class="verbatim"&gt;C-c C-c&lt;/code&gt; keybinding&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-headline-12" class="outline-2"&gt;
&lt;h2 id="headline-12"&gt;
Conclusion
&lt;/h2&gt;
&lt;div id="outline-text-headline-12" class="outline-text-2"&gt;
&lt;p&gt;This example demonstrates key concepts in Emacs mode development:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Creating a new major mode&lt;/li&gt;
&lt;li&gt;Managing buffer-local state&lt;/li&gt;
&lt;li&gt;Handling file persistence&lt;/li&gt;
&lt;li&gt;Adding interactive elements&lt;/li&gt;
&lt;li&gt;Setting up key bindings&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can use these patterns to create more complex modes for your specific needs.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
]]&gt;</content:encoded></item></channel></rss>