From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Jeremy Bryant via "Bug reports for GNU Emacs, the Swiss army knife of text editors" Newsgroups: gmane.emacs.bugs Subject: bug#73016: Potential inclusion of kbd-mode, part of kmonad, in Non-GNU ELPA Date: Tue, 03 Sep 2024 23:19:01 +0100 Message-ID: <875xrcfkiy.fsf@jeremybryant.net> Reply-To: Jeremy Bryant Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="33761"; mail-complaints-to="usenet@ciao.gmane.io" Cc: Tony Zorman To: 73016@debbugs.gnu.org, philipk@posteo.net Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Wed Sep 04 00:20:17 2024 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1slbsm-0008dT-6D for geb-bug-gnu-emacs@m.gmane-mx.org; Wed, 04 Sep 2024 00:20:16 +0200 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1slbsX-0004Bg-48; Tue, 03 Sep 2024 18:20:01 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1slbsV-0004Az-O3 for bug-gnu-emacs@gnu.org; Tue, 03 Sep 2024 18:19:59 -0400 Original-Received: from debbugs.gnu.org ([2001:470:142:5::43]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1slbsV-0000re-E2 for bug-gnu-emacs@gnu.org; Tue, 03 Sep 2024 18:19:59 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=debbugs.gnu.org; s=debbugs-gnu-org; h=MIME-Version:Date:From:To:Subject; bh=sYwrECLLNzRBsWcK2vByEsRbruW1+puby50ghR4AQJs=; b=qkG5+Zcwucv2diUXudv06r+gxfeG8bYq4nYUWxAtMoHGzh1WT3Kh6ZDIzx/61MDfxZy2G8n9Epo81G5mw8UGrgw9s1WQOgwnmBuMsjqhHzpBNh/VbERp0UsVx2qzr0BjV90c+ylZxTIX+wh1utOH5bVMiAffPksf2YHfrixlHbSjRjGm007dUDF2Q8S5sLLZZiPYR+v7kfJaBUhj3/BhGzI6z+WBKRo5wWW2lbrrOi2l9Q60gDs4Bqd5NoCR0c69suXiNbqUHY0SA9MOVWj9pfaL2Nb5gccRaD42W5ggnhYykZmhFT27W11orj1RoHR4cwV2h4nrLNND+4qNU43I5w==; Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1slbtW-0001pO-5S for bug-gnu-emacs@gnu.org; Tue, 03 Sep 2024 18:21:02 -0400 X-Loop: help-debbugs@gnu.org Resent-From: Jeremy Bryant Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Tue, 03 Sep 2024 22:21:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: report 73016 X-GNU-PR-Package: emacs X-Debbugs-Original-To: bug-gnu-emacs@gnu.org, Philip Kaludercic Original-Received: via spool by submit@debbugs.gnu.org id=B.17254020196960 (code B ref -1); Tue, 03 Sep 2024 22:21:02 +0000 Original-Received: (at submit) by debbugs.gnu.org; 3 Sep 2024 22:20:19 +0000 Original-Received: from localhost ([127.0.0.1]:32959 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1slbsp-0001oC-3P for submit@debbugs.gnu.org; Tue, 03 Sep 2024 18:20:19 -0400 Original-Received: from lists.gnu.org ([209.51.188.17]:46970) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1slbsn-0001o3-85 for submit@debbugs.gnu.org; Tue, 03 Sep 2024 18:20:17 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1slbrm-0002FR-5l for bug-gnu-emacs@gnu.org; Tue, 03 Sep 2024 18:19:14 -0400 Original-Received: from out-189.mta0.migadu.com ([91.218.175.189]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1slbri-0000dD-Un for bug-gnu-emacs@gnu.org; Tue, 03 Sep 2024 18:19:13 -0400 X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=jeremybryant.net; s=key1; t=1725401943; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type; bh=sYwrECLLNzRBsWcK2vByEsRbruW1+puby50ghR4AQJs=; b=Y6Mu3uf1w0rMj8CrrJG6ZQ2/EdecCalQ6GYXJxACuogoZqk/K4KUcZ2C96BCFPEPD1ppeq SYpzo1yeMsv3bOLw1fl5eRAPeEznv1/xFdGL3rqs0cZo9ygVPJeJ74mJtLi1SLU/TEsrTU iRryHaJJw5LvjCT/ao522qXyz4VQcv/H6DwZ//ZxiDup994zNj0NjqcOq0Sl9W4o03Bnjx gBDJ10RCt+GnoBjXWsy0AarXnXJ1CLmQirDbSRK1z7g9wXg/LaHGLZezexW9156upG86cw 0AQDZrpfRNDp/3MHezlkoty08DA2QVHHQSxLWHpmz/vtpRO/2sp0JbwQ4z2IJA== X-Migadu-Flow: FLOW_OUT Received-SPF: pass client-ip=91.218.175.189; envelope-from=jb@jeremybryant.net; helo=out-189.mta0.migadu.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Original-Sender: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Xref: news.gmane.io gmane.emacs.bugs:291169 Archived-At: --=-=-= Content-Type: text/plain Hi, kmonad is a keyboard configuration tool under MIT license. https://github.com/kmonad/kmonad There is an Emacs major mode to edit the configuration file, based on s-expressions. The mode is under GPLv3. https://github.com/kmonad/kbd-mode On behalf of the author, Tony Zorman, I would like to request consideration to include it in NON-GNU ELPA. The author is conscious that the following snippet should be improved and we are soliciting recommendations on how to improve it. ;; HACK (defadvice redisplay (after refresh-font-locking activate) (when (derived-mode-p 'kbd-mode) (font-lock-fontify-buffer)))) Furthermore if there are any code reviews or recommendations, I attach the current version. I can volunteer some time for some of the changes. --=-=-= Content-Type: application/emacs-lisp Content-Disposition: attachment; filename=kbd-mode.el Content-Transfer-Encoding: quoted-printable ;;; kbd-mode.el --- Font locking for kmonad's .kbd files -*- lexical-bindin= g: t -*- ;; Copyright 2020=E2=80=932022 slotThe ;; URL: https://github.com/kmonad/kbd-mode ;; Version: 0.0.1 ;; Package-Requires: ((emacs "24.3")) ;; This file is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) ;; any later version. ;; ;; This file is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see . ;;; Commentary: ;; This file adds basic font locking support for `.kbd' configuration ;; files. ;; ;; To use this file, move it to a directory within your `load-path' and ;; require it. For example --- assuming that this file was placed ;; within the `~/.config/emacs/elisp' directory: ;; ;; (add-to-list 'load-path "~/.config/emacs/elisp/") ;; (require 'kbd-mode) ;; ;; If you use `use-package', you can express the above as ;; ;; (use-package kbd-mode ;; :load-path "~/.config/emacs/elisp/") ;; ;; By default we highlight all keywords; you can change this by ;; customizing the `kbd-mode-' variables. For example, to disable the ;; highlighting of already defined macros (i.e. of "@macro-name"), you ;; can set `kbd-mode-show-macros' to `nil'. ;; ;; For keybindings, as well as commentary on the `kbd-mode-demo-mode' ;; minor mode, see the associated README.md file. ;;; Code: (require 'compile) (defgroup kbd nil "Major mode for editing `.kbd' files." :group 'languages) (defgroup kbd-demo nil "A minor mode to test your configuration." :group 'kbd) ;;;; Custom variables (defgroup kbd-highlight nil "Syntax highlighting for `kbd-mode'." :group 'kbd) (defcustom kbd-mode-kexpr '("defcfg" "defsrc" "defalias") "A K-Expression." :type '(repeat string) :group 'kbd-highlight) ;; HACK (defcustom kbd-mode-function-one '("deflayer") "Tokens that are treated as functions with one argument." :type '(repeat string) :group 'kbd-highlight) (defcustom kbd-mode-tokens '(;; input tokens "uinput-sink" "send-event-sink" "kext" ;; output tokens "device-file" "low-level-hook" "iokit-name") "Input and output tokens." :type '(repeat string) :group 'kbd-highlight) (defcustom kbd-mode-defcfg-options '("input" "output" "cmp-seq-delay" "cmp-seq" "init" "fallthrough" "allow-= cmd") "Options to give to `defcfg'." :type '(repeat string) :group 'kbd-highlight) (defcustom kbd-mode-button-modifiers '("around-next-timeout" "around-next-single" "around-next" "around" "tap-hold-next-release" "tap-hold-next" "tap-next-release" "tap-hold" "tap-macro-release" "tap-macro" "multi-tap" "tap-next" "layer-toggle" "layer-switch" "layer-add" "layer-rem" "layer-delay" "layer-next" "cmd-= button") "Button modifiers." :type '(repeat string) :group 'kbd-highlight) (defcustom kbd-mode-show-string '("uinput-sink" "device-file" "cmd-button") "Syntax highlight strings in S-expressions. When an S-expression begins with any of these keywords, highlight strings (delimited by double quotes) inside it." :type '(repeat string) :group 'kbd-highlight) (defcustom kbd-mode-show-macros t "Whether to syntax highlight macros inside layout definitions. Default: t" :type 'boolean :group 'kbd-highlight) (defcustom kbd-mode-magic-focus nil "Whether to enable magic focus. Whenever the `kbd-mode-demo-mode' buffer gets focused, automatically start try to start a new process for the config file. When switching back to the config file, kill that process. Default: nil" :type 'boolean :group 'kbd-demo) (defcustom kbd-mode-kill-kmonad nil "How to kill (or suspend) a running kmonad instance. This is used when invoking `kbd-mode-start-demo' and, in general, when entering `kbd-mode-demo-mode' because keyboards can't be grabbed twice." :type 'string :group 'kbd-demo) (defcustom kbd-mode-start-kmonad nil "How to restart (or resume) kmonad. If there was an active kmonad instance running, which was killed by `kbd-mode-kill-kmonad', then this (re)starts kmonad with the given command upon exiting `kbd-mode-demo-mode'." :type 'string :group 'kbd-demo) ;;;; Faces (defgroup kbd-highlight-faces nil "Faces used for highlighting in `kbd-mode'." :group 'kbd-highlight) (defface kbd-mode-kexpr-face '((t :inherit font-lock-keyword-face)) "Face for a K-Expression." :group 'kbd-highlight-faces) (defface kbd-mode-token-face '((t :inherit font-lock-function-name-face)) "Face for input and output tokens." :group 'kbd-highlight-faces) (defface kbd-mode-defcfg-option-face '((t :inherit font-lock-builtin-face)) "Face for options one may give to `defcfg'." :group 'kbd-highlight-faces) (defface kbd-mode-button-modifier-face '((t :inherit font-lock-function-name-face)) "Face for all the button modifiers." :group 'kbd-highlight-faces) (defface kbd-mode-variable-name-face '((t :inherit font-lock-variable-name-face)) "Face for a variables, i.e. layer names, macros in layers,..." :group 'kbd-highlight-faces) (defface kbd-mode-string-face '((t :inherit font-lock-string-face)) "Face for strings." :group 'kbd-highlight-faces) ;;;; Functions (defun kbd-mode--show-macros? (show-macros) "Decide whether to font-lock macros. If the argument SHOW-MACROS is non-nil, font-lock macros of the form `@MACRO-NAME' with `kbd-mode-variable-name-face'." (let ((macro-regexp '(("\\(:?\\(@[^[:space:]]+\\)\\)" (1 'kbd-mode-variable-name-face))))) (if show-macros (font-lock-add-keywords 'kbd-mode macro-regexp) (font-lock-remove-keywords 'kbd-mode macro-regexp)))) ;;; Vars (defvar kbd-mode-syntax-table (let ((st (make-syntax-table))) ;; Use ;; for regular comments and #| |# for line comments. (modify-syntax-entry ?\; ". 12b" st) (modify-syntax-entry ?\n "> b" st) (modify-syntax-entry ?\# ". 14" st) (modify-syntax-entry ?\| ". 23" st) ;; We don't need to highlight brackets, as they're only used inside ;; layouts. (modify-syntax-entry ?\[ "." st) (modify-syntax-entry ?\] "." st) ;; We highlight the necessary strings ourselves. (modify-syntax-entry ?\" "." st) st) "The basic syntax table for `kbd-mode'.") (defvar kbd-mode--font-lock-keywords (let ((kexpr-regexp (regexp-opt kbd-mode-kexpr 'wor= ds)) (token-regexp (regexp-opt kbd-mode-tokens 'wor= ds)) (defcfg-options-regexp (regexp-opt kbd-mode-defcfg-options 'wor= ds)) (button-modifiers-regexp (regexp-opt kbd-mode-button-modifiers 'wor= ds)) (function-one-regexp (concat "\\(?:\\(" (regexp-opt kbd-mode-function-one) "\\)\\([[:space:]]+[[:word:]]+\\)\\)")) ;; Only highlight these strings; configuration files may explicitly ;; use a " to emit a double quote, so we can't trust the default ;; string highlighting. (string-regexp (concat "\\(['\(]" (regexp-opt kbd-mode-show-string) "\\)\\(\\S)+\\)\)"))) `((,token-regexp (1 'kbd-mode-token-face )) (,kexpr-regexp (1 'kbd-mode-kexpr-face )) (,button-modifiers-regexp (1 'kbd-mode-button-modifier-face)) (,defcfg-options-regexp (1 'kbd-mode-defcfg-option-face )) (,function-one-regexp (1 'kbd-mode-kexpr-face ) (2 'kbd-mode-variable-name-face)) (,string-regexp ("\"[^}]*?\"" (progn (goto-char (match-beginning 0)) (match-end 0)) (goto-char (match-end 0)) (0 'kbd-mode-string-face t))))) "Keywords to be syntax highlighted.") ;;; Define Major Mode ;; Because the configuration language is in a lispy syntax, we can ;; inherit from any lisp mode in order to get good parenthesis handling ;; for free. (defvar kbd-mode-map (let ((map (make-sparse-keymap))) (define-key map (kbd "C-c C-c") #'kbd-mode-start-demo) (define-key map (kbd "C-c C-z") #'kbd-mode-switch) map)) ;;;###autoload (define-derived-mode kbd-mode emacs-lisp-mode "Kbd" "Major mode for editing `.kbd' files. For details, see `https://github.com/kmonad/kmonad'." (set-syntax-table kbd-mode-syntax-table) (use-local-map kbd-mode-map) (font-lock-add-keywords 'kbd-mode kbd-mode--font-lock-keywords) (kbd-mode--show-macros? kbd-mode-show-macros) ;; HACK (defadvice redisplay (after refresh-font-locking activate) (when (derived-mode-p 'kbd-mode) (font-lock-fontify-buffer)))) ;; Associate the `.kbd' ending with `kbd-mode'. ;;;###autoload (add-to-list 'auto-mode-alist '("\\.kbd\\'" . kbd-mode)) ;;;; Demo Minor Mode (defvar kbd-mode-demo-file nil "Path to the users configuration file. This is used in `kbd-mode-demo-mode' for deciding what configuration to compile.") (defvar kbd-mode-had-kmonad? nil "Whether the user had a running kmonad instance. This controls whether kmonad will be restarted by mean of `kbd-mode-start-kmonad' after exiting `kbd-mode-demo-mode'.") (defvar kbd-mode-demo-mode-map (let ((map (make-sparse-keymap))) (define-key map (kbd "C-c C-c") #'kbd-mode-stop-demo) (define-key map (kbd "C-c C-z") #'kbd-mode-switch) map)) ;;;###autoload (define-minor-mode kbd-mode-demo-mode "Toggle kmonad demo mode. This is a minor mode, in which users can test their configurations." :lighter " kbd-demo" :keymap kbd-mode-demo-mode-map (when kbd-mode-demo-mode (unless (kbd-mode--valid-config?) (kbd-mode--show-error))) ;; Handle toggle (when kbd-mode-magic-focus (cond (kbd-mode-demo-mode (add-hook 'window-selection-change-functions #'kbd-mode--toggle-= demo nil t) (add-hook 'focus-in-hook #'kbd-mode--create-kmonad-process nil t) (add-hook 'focus-out-hook #'kbd-mode--kill-demo-process nil t)) (t (remove-hook 'window-selection-change-functions #'kbd-mode--togg= le-demo t) (remove-hook 'focus-in-hook #'kbd-mode--create-kmonad-process t) (remove-hook 'focus-out-hook #'kbd-mode--kill-demo-process t))))) ;;;; Interactive Functions ;;;###autoload (defun kbd-mode-start-demo () "Try the current configuration in a demo buffer. Use `kbd-mode-stop-demo' to stop the demo. If the configuration file has errors, the demo will not start and an error buffer will be shown instead." (interactive) (setq kbd-mode-demo-file (kbd-mode--find-kbd-file (buffer-file-name (current-buffer)))) (if (not (kbd-mode--valid-config?)) (kbd-mode--show-error) (when (shell-command "ps -C kmonad") (setq kbd-mode-had-kmonad? t) (kbd-mode--kill-kmonad)) (kbd-mode--create-demo-buffer) (pop-to-buffer "*kmonad-demo*") (kbd-mode--create-kmonad-process) (kbd-mode-demo-mode t))) (defun kbd-mode-stop-demo () "Stop the currently running demo." (interactive) (with-current-buffer "*kmonad-demo*" (kbd-mode-demo-mode 0) (kill-buffer-and-window) (kbd-mode--kill-demo-process) (when kbd-mode-had-kmonad? (kbd-mode--start-kmonad)))) (defun kbd-mode-switch () "Switch between the demo window and the config file." (interactive) (select-window (get-buffer-window (if (and (equal (buffer-name) "*kmonad-demo*") kbd-mode-demo-mode) (get-file-buffer kbd-mode-demo-file) "*kmonad-demo*")))) ;;;; Helper Functions (defun kbd-mode--create-demo-buffer () "Create the *kmonad-demo* buffer." (unless (get-buffer "*kmonad-demo*") (display-buffer (get-buffer-create "*kmonad-demo*") '(display-buffer-at-bottom (window-height . 0.15))))) (defun kbd-mode--find-kbd-file (&optional file) "Find the config file. If the optional argument FILE is given, use it instead. Otherwise, prompt the user for a choice." (if (and file (string=3D (file-name-extension file) "kbd")) file (expand-file-name (read-file-name "Choose configuration file")))) (defun kbd-mode--valid-config? () "Check if the current configuration is valid." (let ((command (kbd-mode--get-config-validation-command))) (eq 0 (shell-command command)))) (defun kbd-mode--create-kmonad-process () "Start the kmonad demo process in a dedicated buffer." (when (get-buffer-process "*kmonad*") (kbd-mode--kill-demo-process)) (start-process "kmonad-emacs" "*kmonad*" "kmonad" kbd-mode-demo-file)) (defun kbd-mode--kill-demo-process () "Kill demo kmonad process, if possible." (when (get-buffer-process "*kmonad*") (kill-process "*kmonad*"))) (defun kbd-mode--kill-kmonad () "Kill (or suspend) a running kmonad instance. The command used to kill kmonad is given by the `kbd-mode-kill-kmonad' variable." (if kbd-mode-kill-kmonad (shell-command kbd-mode-kill-kmonad) (error "To kill the running kmonad instance, customize the `kbd-mode-ki= ll-kmonad' variable!"))) (defun kbd-mode--start-kmonad () "Start (or resume) a new kmonad process. The command used to start kmonad is given by the `kbd-mode-start-kmonad' variable." (if kbd-mode-kill-kmonad (call-process-shell-command ;; Force the command to be executed asynchronously. (if (eq (aref kbd-mode-start-kmonad (1- (length kbd-mode-start-kmonad))) ?&) kbd-mode-start-kmonad (concat kbd-mode-start-kmonad "&"))) (error "To restart kmonad, customize the `kbd-mode-start-kmonad' variab= le!"))) (defun kbd-mode--toggle-demo (&optional _window) "Toggle the kmonad demo process. When the users exits the demo window, kill the demo process and start a \"normal\" kmonad process instead. When re-entering the demo window, do the opposite; i.e., kill the running kmonad instance and spawn a demo process." (cond ((kbd-mode--was-demo?) (kbd-mode--kill-demo-process) (kbd-mode--start-kmonad)) ((kbd-mode--valid-config?) (kbd-mode--kill-kmonad) (kbd-mode--create-kmonad-process)) (t (kbd-mode--start-kmonad) (kbd-mode--show-error)))) (defun kbd-mode--was-demo? () "Was the previous buffer the kmonad demo buffer?" (equal (window-buffer (previous-window)) (get-buffer "*kmonad-demo*"))) (defun kbd-mode--show-error () "Show configuration errors in a compilation buffer." (when kbd-mode-demo-mode (quit-window 'kill "*kmonad-demo*")) (compile (kbd-mode--get-config-validation-command))) (defun kbd-mode--get-config-validation-command () "Get validation command for `kbd-mode-demo-file'." (concat "kmonad -d " kbd-mode-demo-file)) ;;;; Integration with `compilation-mode' (add-to-list 'compilation-error-regexp-alist 'kbd) (add-to-list 'compilation-error-regexp-alist-alist '(kbd "^kmonad: Parse error at \\([0-9]+\\):\\([0-9]+\\)" nil = 1 2)) (provide 'kbd-mode) ;;; kbd-mode.el ends here --=-=-=--