cosmopolitan/tool/emacs/cosmo-format.el
Justine Tunney b45d50b690 Make improvements
- Fix build flakes
- Polyfill SIGWINCH on Windows
- Fix an execve issue on Windows
- Make strerror show more information
- Improve cmd.exe setup/teardown on Windows
- Support bracketed paste mode in Blinkenlights
- Show keyboard shortcuts in Blinkenlights status bar
- Fixed copy_file_range() and copyfile() w/ zip filesystem
- Size optimize GetDosArgv() to keep life.com 12kb in size
- Improve Blinkenlights ability to load weird ELF executables
- Fix program_executable_name and add GetInterpreterExecutableName
- Make Python in tiny mode fail better if docstrings are requested
- Update Python test exclusions in tiny* modes such as tinylinux
- Add bulletproof unbreakable kprintf() troubleshooting function
- Remove "oldskool" keyword from ape.S for virus scanners
- Fix issue that caused backtraces to not print sometimes
- Improve Blinkenlights serial uart character i/o
- Make clock_gettime() not clobber errno on xnu
- Improve sha256 cpuid check for old computers
- Integrate some bestline linenoise fixes
- Show runit process names better in htop
- Remove SIGPIPE from ShowCrashReports()
- Make realpath() not clobber errno
- Avoid attaching GDB on non-Linux
- Improve img.com example
2022-03-16 13:40:10 -07:00

133 lines
4.6 KiB
EmacsLisp

;;; cosmo-format.el --- Cosmopolitan Clang-Format Integration
;; Author: Justine Tunney <jtunney@gmail.com>
;; Version: 0.1.0
;; License: Public Domain
;; Keywords: c c++ clang
;; To the extent possible under law, Justine Tunney has waived all
;; copyright and related or neighboring rights to this file, as it is
;; written in the following disclaimers: <http://unlicense.org/> and
;; <http://creativecommons.org/publicdomain/zero/1.0/>
;;; Commentary:
;;
;; This module automates indentation, whitespace, and other stylistic
;; concerns while editing C/C++ source files. The clang-format program,
;; if present on the system, is run each time a buffer is saved.
;;; Installation:
;;
;; Put the following in your .emacs.d/init.el file:
;;
;; (require 'cosmo-format)
;;
;; Put this file in the root of your project:
;;
;; printf '---\nBasedOnStyle: Google\n...\n' >.clang-format
;;
;; Any buffer whose pathname matches `cosmo-format-path-regex' will
;; be formatted automatically on save if:
;;
;; 1. It's able to find the clang-format program, or
;; `cosmo-format-bin' is customized.
;;
;; 2. There's a .clang-format file up the directory tree, or
;; `cosmo-format-arg' is customized; in which case, it is
;; recommended that it be customized buffer locally.
;;
;; For all other cases, there are no latency penalties (i.e. superfluous
;; i/o syscalls) or risks to leaving this enabled globally.
;;; Code:
(defcustom cosmo-format-bin nil
"Explicit command or pathname of clang-format program."
:type 'string
:group 'cosmo-format)
(defcustom cosmo-format-arg nil
"Explicit argument to clang-format program."
:type 'string
:group 'cosmo-format)
(defcustom cosmo-format-modes '(c-mode
c++-mode
java-mode
protobuf-mode)
"List of major-modes that need clang-format."
:type '(repeat symbol)
:group 'cosmo-format)
(defcustom cosmo-format-exts '("c" "cc" "h" "inc" ;; c/c++
"hh" "cpp" "hpp" ;; ms c/c++
"rl" ;; ragel
"proto") ;; protobuf
"List of pathname extensions that need clang-format."
:type '(repeat string)
:group 'cosmo-format)
(defcustom cosmo-format-blacklist '("quickjs.c")
"List of files to ignore, matched by basename."
:type '(repeat string)
:group 'cosmo-format)
(defvar cosmo--clang-format-bin)
(defmacro cosmo-memoize (var mvar form)
"Return VAR or evaluate FORM memoized locally to MVAR."
`(cond (,var ,var)
((fboundp (quote ,mvar))
(cond ((eq ,mvar 'null) nil)
(t ,mvar)))
(t (let ((res ,form))
(setq-local ,mvar (or res 'null))
res))))
(defun cosmo--find-clang-format-bin ()
(cosmo-memoize cosmo-format-bin
cosmo--clang-format-bin
(or (executable-find "clang-format-10")
(executable-find "clang-format-9")
(executable-find "clang-format-8")
(executable-find "clang-format-7")
(executable-find "clang-format"))))
(defun cosmo-format ()
"Beautifies source code in current buffer."
(interactive)
(when (and (memq major-mode cosmo-format-modes)
(member (file-name-extension (buffer-file-name))
cosmo-format-exts)
(not (member (file-name-nondirectory (buffer-name))
cosmo-format-blacklist))
(not (save-excursion
(beginning-of-buffer)
(looking-at "/\\* clang-format off \\*/"))))
(let ((bin (cosmo--find-clang-format-bin)))
(when bin
(let ((p (point))
(tmp (make-temp-file "cosmo-format"))
(arg (or cosmo-format-arg
(and (locate-dominating-file
(buffer-file-name)
".clang-format")
"-style=file"))))
(when arg
(message arg)
(write-region nil nil tmp)
(let ((buf (get-buffer-create "*clang-format*"))
(exe (cosmo--find-clang-format-bin)))
(with-current-buffer buf
(call-process exe tmp t nil arg))
(replace-buffer-contents buf)
(kill-buffer buf)
(delete-file tmp nil))))))))
;; Emacs 26.3+ needed for replace-buffer-contents; so worth it!!
(unless (version-list-< (version-to-list emacs-version) '(26 3))
(add-hook 'before-save-hook 'cosmo-format))
(provide 'cosmo-format)
;;; cosmo-format.el ends here