801 lines
29 KiB
EmacsLisp
801 lines
29 KiB
EmacsLisp
;; ╔──────────────────────────────────────────────────────────────────╗
|
||
;; │ 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/ │
|
||
;; │ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||
;; ╚──────────────────────────────────────────────────────────────────╝
|
||
;; Hodgepodge of copypasta from Justine's Emacs config intended to be
|
||
;; helpful to those wanting to configure their own Emacs editor to work
|
||
;; pretty well as a Cosmopolitan IDE.
|
||
|
||
;;; Code:
|
||
|
||
(require 'asm-mode)
|
||
(require 'cc-mode)
|
||
(require 'fortran)
|
||
(require 'cosmo-c-types)
|
||
(require 'cosmo-c-keywords)
|
||
(require 'cosmo-c-builtins)
|
||
(require 'cosmo-c-constants)
|
||
(require 'cosmo-cpp-constants)
|
||
(require 'cosmo-platform-constants)
|
||
(require 'dired)
|
||
(require 'javadown)
|
||
(require 'ld-script)
|
||
(require 'make-mode)
|
||
|
||
(setq c-doc-comment-style 'javadown)
|
||
|
||
(add-to-list 'auto-mode-alist '("\\.x$" . c-mode)) ;; -aux-info
|
||
|
||
|
||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
;; Support Macros
|
||
|
||
(defmacro setql (var val)
|
||
`(set (make-local-variable ',var) ,val))
|
||
|
||
|
||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
;; Support Functions
|
||
|
||
(defun cosmo-contains (x s &optional icase)
|
||
(declare (pure t) (side-effect-free t))
|
||
(let ((case-fold-search icase))
|
||
(not (null (string-match-p (regexp-quote x) s)))))
|
||
|
||
(defun cosmo-startswith (x s &optional icase)
|
||
(declare (pure t) (side-effect-free t))
|
||
(not (null (string-prefix-p x s icase))))
|
||
|
||
(defun cosmo-endswith (x s &optional icase)
|
||
(declare (pure t) (side-effect-free t))
|
||
(let ((p (- (length s) (length x))))
|
||
(and (>= p 0)
|
||
(eq t (compare-strings x nil nil
|
||
s p nil icase)))))
|
||
|
||
(defun cosmo-replace (x y s)
|
||
(declare (pure t) (side-effect-free t))
|
||
(let ((case-fold-search nil))
|
||
(replace-regexp-in-string (regexp-quote x) y s t t)))
|
||
|
||
(defun cosmo-join (s l)
|
||
(declare (pure t) (side-effect-free t))
|
||
(mapconcat 'identity l s))
|
||
|
||
(defun cosmo-lchop (p s)
|
||
(declare (pure t) (side-effect-free t))
|
||
(if (and (>= (length s) (length p))
|
||
(string= p (substring s 0 (length p))))
|
||
(substring s (length p))
|
||
s))
|
||
|
||
(defun cosmo-first-that (predicate list)
|
||
(declare (pure t))
|
||
(when list
|
||
(if (funcall predicate (car list))
|
||
(car list)
|
||
(cosmo-first-that predicate (cdr list)))))
|
||
|
||
(defun cosmo-file-name-sans-extensions (filename)
|
||
(save-match-data
|
||
(let (directory
|
||
(file (file-name-sans-versions
|
||
(file-name-nondirectory filename))))
|
||
(if (and (string-match "[.-].*\\'" file)
|
||
(not (eq 0 (match-beginning 0))))
|
||
(if (setq directory (file-name-directory filename))
|
||
(concat directory (substring file 0 (match-beginning 0)))
|
||
(substring file 0 (match-beginning 0)))
|
||
filename))))
|
||
|
||
|
||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
;; C-c . Jump to symbol definition
|
||
;; C-c , Jump back to where we were
|
||
;; C-c C-i Show references to symbol
|
||
|
||
;; TODO(jart): Why doesnt the default-directory variable work?
|
||
(defun project-current (&optional maybe-prompt dir)
|
||
(expand-file-name
|
||
(file-name-directory
|
||
(locate-dominating-file
|
||
(buffer-name) "Makefile"))))
|
||
|
||
(defun cosmo-xref-find-references ()
|
||
(interactive)
|
||
(let ((case-fold-search nil))
|
||
(xref-find-references (format "%S" (symbol-at-point)))))
|
||
|
||
(defun cosmo-xref-find-definitions ()
|
||
(interactive)
|
||
(let ((case-fold-search nil))
|
||
(xref-find-definitions (format "%S" (symbol-at-point)))))
|
||
|
||
(global-set-key (kbd "M-,") 'xref-pop-marker-stack)
|
||
(global-set-key (kbd "M-.") 'cosmo-xref-find-definitions)
|
||
(global-set-key (kbd "C-c TAB") 'cosmo-xref-find-references)
|
||
|
||
(defun stop-asking-questions-etags ()
|
||
(set (make-local-variable 'tags-file-name)
|
||
(format "%s/TAGS"
|
||
(or (locate-dominating-file (buffer-name) "Makefile")
|
||
(file-name-directory (buffer-name))))))
|
||
(add-hook 'c-mode-common-hook 'stop-asking-questions-etags)
|
||
(setq tags-revert-without-query t)
|
||
(setq kill-buffer-query-functions ;; disable kill buffer w/ process question
|
||
(delq 'process-kill-buffer-query-function kill-buffer-query-functions))
|
||
|
||
|
||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
;; Compile buffer and run associated test and/or display assembly
|
||
;; C-c C-c Compile
|
||
;; M-1 C-c C-c Compile w/ MODE=tiny
|
||
;; M-2 C-c C-c Compile w/ MODE=opt
|
||
;; M-3 C-c C-c Compile w/ MODE=rel
|
||
;; M-4 C-c C-c Compile w/ MODE=dbg
|
||
;; M-5 C-c C-c Compile w/ MODE=""
|
||
;; M-9 C-c C-c Compile w/ chibicc
|
||
|
||
(defun cosmo-intest (&optional file-name)
|
||
(let (path root pkg)
|
||
(and (setq path (or (buffer-file-name) dired-directory))
|
||
(setq root (locate-dominating-file path "Makefile"))
|
||
(setq pkg (file-relative-name path root))
|
||
(cosmo-startswith "test/" pkg))))
|
||
|
||
(defun cosmo--make-mode (arg &optional default)
|
||
(cond ((eq arg 1) "tiny")
|
||
((eq arg 2) "opt")
|
||
((eq arg 3) "rel")
|
||
((eq arg 4) "dbg")
|
||
((eq arg 5) "")
|
||
(default default)
|
||
((cosmo-intest) "dbg")
|
||
(t "")))
|
||
|
||
(defun cosmo--make-suffix (arg)
|
||
(cond ((eq arg 9) ".chibicc")
|
||
(t "")))
|
||
|
||
(defun cosmo--make-objdump-flags (arg)
|
||
(cond ((eq arg 9) "-x")
|
||
(t "")))
|
||
|
||
(defun cosmo--compile-command (this root kind mode suffix objdumpflags)
|
||
(let* ((ext (file-name-extension this)) ;; e.g. "c"
|
||
(dir (file-name-directory this)) ;; e.g. "/home/jart/daisy/libc/"
|
||
(dots (file-relative-name root dir)) ;; e.g. "../"
|
||
(file (file-relative-name this root)) ;; e.g. "libc/crc32c.c"
|
||
(name (file-name-sans-extension file)) ;; e.g. "libc/crc32c"
|
||
(buddy (format "test/%s_test.c" name))
|
||
(runs (format "o/$m/%s.com.runs TESTARGS=-b" name))
|
||
(buns (format "o/$m/test/%s_test.com.runs TESTARGS=-b" name)))
|
||
(cond ((not (member ext '("c" "cc" "s" "S" "rl" "f")))
|
||
(format "m=%s; make -j8 -O MODE=$m SILENT=0 o/$m/%s"
|
||
mode
|
||
(directory-file-name
|
||
(file-name-directory
|
||
(file-relative-name this root)))))
|
||
((and (equal suffix "")
|
||
(cosmo-contains "_test." (buffer-file-name)))
|
||
(format "m=%s; make -j8 -O MODE=$m %s"
|
||
mode runs))
|
||
((and (equal suffix "")
|
||
(file-exists-p (format "%s" buddy)))
|
||
(format (cosmo-join
|
||
" && "
|
||
'("m=%s; n=%s; make -j8 -O o/$m/$n%s.o MODE=$m SILENT=0"
|
||
;; "bloat o/$m/%s.o | head"
|
||
;; "nm -C --size o/$m/%s.o | sort -r"
|
||
"echo"
|
||
"size -A o/$m/$n.o | grep '^[.T]' | grep -v 'debug\\|command.line\\|stack' | sort -rnk2"
|
||
"objdump %s -wzCd o/$m/$n%s.o"))
|
||
mode name suffix objdumpflags suffix))
|
||
((eq kind 'run)
|
||
(format
|
||
(cosmo-join
|
||
" && "
|
||
`("m=%s; f=o/$m/%s.com"
|
||
,(concat "make -j8 -O $f MODE=$m SILENT=0")
|
||
"./$f"))
|
||
mode name))
|
||
((and (file-regular-p this)
|
||
(file-executable-p this))
|
||
(format "./%s" file))
|
||
('t
|
||
(format
|
||
(cosmo-join
|
||
" && "
|
||
`("m=%s; f=o/$m/%s%s.o"
|
||
,(concat "make -j8 -O $f MODE=$m SILENT=0")
|
||
;; "nm -C --size $f | sort -r"
|
||
"echo"
|
||
"size -A $f | grep '^[.T]' | grep -v 'debug\\|command.line\\|stack' | sort -rnk2"
|
||
"objdump %s -wzCd $f"))
|
||
mode name suffix objdumpflags)))))
|
||
|
||
(defun cosmo-compile (arg)
|
||
(interactive "P")
|
||
(let* ((this (or (buffer-file-name) dired-directory))
|
||
(root (locate-dominating-file this "Makefile")))
|
||
(when root
|
||
(let* ((mode (cosmo--make-mode arg))
|
||
(suffix (cosmo--make-suffix arg))
|
||
(objdumpflags (cosmo--make-objdump-flags arg))
|
||
(compilation-scroll-output nil)
|
||
(default-directory root)
|
||
(compile-command (cosmo--compile-command this root nil mode suffix objdumpflags)))
|
||
(compile compile-command)))))
|
||
|
||
(defun cosmo-compile-hook ()
|
||
(local-set-key (kbd "C-c C-c") 'cosmo-compile))
|
||
|
||
(progn
|
||
(add-hook 'makefile-mode-hook 'cosmo-compile-hook)
|
||
(add-hook 'asm-mode-hook 'cosmo-compile-hook)
|
||
(add-hook 'ld-script-mode-hook 'cosmo-compile-hook)
|
||
(add-hook 'dired-mode-hook 'cosmo-compile-hook)
|
||
(add-hook 'c-mode-common-hook 'cosmo-compile-hook)
|
||
(add-hook 'fortran-mode-hook 'cosmo-compile-hook)
|
||
(add-hook 'protobuf-mode-hook 'cosmo-compile-hook))
|
||
|
||
|
||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
;; Display assembly for C/C++ buffer
|
||
;;
|
||
;; C-c C-a Compile and show assembly, with a native optimized build
|
||
;; C-c C-b Compile and show assembly, with a balanced build
|
||
;;
|
||
;; The ALT key may be used to override the default mode.
|
||
;;
|
||
;; M-1 C-c C-a Compile w/ MODE=tiny
|
||
;; M-2 C-c C-a Compile w/ MODE=opt
|
||
;; M-3 C-c C-a Compile w/ MODE=rel
|
||
;; M-4 C-c C-a Compile w/ MODE=dbg
|
||
;; M-5 C-c C-a Compile w/ MODE=""
|
||
;;
|
||
|
||
(defvar cosmo--assembly-root nil)
|
||
(defvar cosmo--assembly-pending nil)
|
||
|
||
(defun cosmo--scrub (regex replace)
|
||
(replace-regexp regex replace nil (point-min) (point-max)))
|
||
|
||
(defun cosmo--fixup-asm ()
|
||
(cosmo--scrub
|
||
;; Code like this
|
||
;;
|
||
;; .section "GNU!GNU!GNU!.must.be.in.every.asm.or.mprotect.breaks"
|
||
;;
|
||
;; Isn't needed since the underlying issue is addressed by ape/ape.S
|
||
;; which generates executable structure.
|
||
" .section .note.GNU-stack,.*,@progbits\n"
|
||
"")
|
||
(cosmo--scrub
|
||
;; Code like this
|
||
;;
|
||
;; and $2047, %edx
|
||
;;
|
||
;; Should be this
|
||
;;
|
||
;; and $2047,%edx
|
||
;;
|
||
;; Per our favored coding style.
|
||
", "
|
||
",")
|
||
(cosmo--scrub
|
||
;; Code like this
|
||
;;
|
||
;; .ascii "foo"
|
||
;; .zero 1
|
||
;;
|
||
;; Should be this
|
||
;;
|
||
;; .ascii "foo"
|
||
;; .zero 1
|
||
;;
|
||
;; @see -frecord-gcc-switches
|
||
"\t\\.ascii\t\"\\([^\"]*\\)\"\n\t\\.zero\t1\n"
|
||
"\t.asciz\t\"\\1\"\n")
|
||
(cosmo--scrub
|
||
;; Code like this
|
||
;;
|
||
;; movl %eax,a
|
||
;; movb b,%bl
|
||
;; movb $1,c
|
||
;; incb d
|
||
;; movq %xmm0,%rax
|
||
;;
|
||
;; Should be this
|
||
;;
|
||
;; mov %eax,a
|
||
;; mov %bl,b
|
||
;; movb $1,c
|
||
;; incb d
|
||
;; movq %xmm0,%rax # ;_;
|
||
;;
|
||
;; Because we dislike redundancy and don't want the
|
||
;; ibmicroborlandtel crowd feeling too uncomfortable.
|
||
(let ((names-a-register
|
||
"%[A-Za-z]")
|
||
(normal-arithmetic-ops
|
||
(regexp-opt
|
||
(list
|
||
"rcr" "rcl" "ror" "rol" "hlt" "cmc" "div" "sar"
|
||
"mov" "shl" "shr" "lea" "cmp" "adc" "sbb" "inc"
|
||
"sub" "xor" "add" "and" "or" "not" "btc" "dec"
|
||
"mul" "neg" "bt" "bsf" "bsr" "int" "test")))
|
||
(prefixes
|
||
(regexp-opt
|
||
(list
|
||
"es" "cs" "ss" "ds" "lock"
|
||
"rep" "repnz" "repne" "repz" "repe"
|
||
"rex.b" "rex.x" "rex.xb" "rex.r" "rex.rb" "rex.rx"
|
||
"rex.rxb" "rex.w" "rex.wb" "rex.wx" "rex.wxb" "rex.wr"
|
||
"rex.trb" "rex.wrx" "rex.wrxb"))))
|
||
(concat "\\("
|
||
"^[ \t]*"
|
||
"\\(?:" prefixes " \\|\\)"
|
||
normal-arithmetic-ops
|
||
"\\)"
|
||
"[bwlq]"
|
||
"\\("
|
||
"[ \t]+"
|
||
"\\(?:"
|
||
"%[A-Wa-w][^\n]+"
|
||
"\\|"
|
||
"[^%][^\n,]*,%[A-Za-z][^\n]+"
|
||
"\\)"
|
||
"\\)"))
|
||
"\\1\\2")
|
||
;; Scroll first function to top of display.
|
||
(goto-char (point-min))
|
||
(when (search-forward-regexp
|
||
"\t\\.type[^\n]*@function" nil t)
|
||
(recenter-top-bottom 'top)))
|
||
|
||
(defun cosmo--assembly-compilation-finished (compilebuf msg)
|
||
(when cosmo--assembly-pending
|
||
(let ((asm-gcc (car cosmo--assembly-pending))
|
||
(asm-clang (cdr cosmo--assembly-pending))
|
||
width
|
||
asm-gcc-buffer
|
||
asm-gcc-window
|
||
asm-clang-buffer
|
||
asm-clang-window)
|
||
(setq cosmo--assembly-pending nil)
|
||
(when (not (cosmo-contains "finished" msg))
|
||
(error "making assembly failed: %s" msg))
|
||
(let ((f (format "%s/%s" cosmo--assembly-root asm-gcc)))
|
||
(when (or (null asm-gcc) (not (file-exists-p f)))
|
||
(error "asm-gcc not found: %s" f)))
|
||
(let ((f (format "%s/%s" cosmo--assembly-root asm-clang)))
|
||
(when (or (null asm-gcc) (not (file-exists-p f)))
|
||
(error "asm-gcc not found: %s" f)))
|
||
(delete-other-windows)
|
||
(setq width (window-total-width))
|
||
(setq asm-gcc-buffer (find-file-noselect asm-gcc t nil nil))
|
||
(setq asm-clang-buffer (find-file-noselect asm-clang t nil nil))
|
||
(setq asm-clang-window (split-window-right (- width (/ width 4))))
|
||
(setq asm-gcc-window (split-window-right (- (- width (/ width 4)) (/ width 4))))
|
||
(set-window-buffer asm-gcc-window asm-gcc-buffer)
|
||
(set-window-buffer asm-clang-window asm-clang-buffer)
|
||
(other-window 1)
|
||
(cosmo--fixup-asm)
|
||
(save-buffer)
|
||
(bury-buffer (current-buffer))
|
||
(other-window 1)
|
||
(cosmo--fixup-asm)
|
||
(save-buffer)
|
||
(bury-buffer (current-buffer))
|
||
(other-window 1)
|
||
(bury-buffer compilebuf))))
|
||
|
||
(defun cosmo--purge-file (path)
|
||
(let ((b (find-file-noselect path t nil nil)))
|
||
(when b
|
||
(with-current-buffer b
|
||
(save-buffer))
|
||
(when (not (kill-buffer b))
|
||
(error "couldn't kill asm buffer"))))
|
||
(delete-file path t))
|
||
|
||
(defun cosmo--assembly (arg extra-make-flags)
|
||
(let* ((this (expand-file-name (or (buffer-file-name) dired-directory)))
|
||
(root (expand-file-name (locate-dominating-file this "Makefile"))))
|
||
(when root
|
||
(let* ((mode (cosmo--make-mode arg "opt"))
|
||
(ext (file-name-extension this))
|
||
(dir (file-name-directory this))
|
||
(dots (file-relative-name root dir))
|
||
(file (file-relative-name this root))
|
||
(name (file-name-sans-extension file))
|
||
(asm-gcc (format "o/%s/%s-gcc.asm" mode name))
|
||
(asm-clang (format "o/%s/%s-clang.asm" mode name)))
|
||
(when (not (member ext '("c" "cc" "f")))
|
||
(error "don't know how to show assembly for non c/c++ source file"))
|
||
(let* ((default-directory root)
|
||
(compile-command
|
||
(format "make %s SILENT=0 -j8 -O MODE=%s %s %s"
|
||
(or extra-make-flags "") mode asm-gcc asm-clang)))
|
||
(save-buffer)
|
||
(set-visited-file-modtime (current-time))
|
||
(cosmo--purge-file asm-gcc)
|
||
(cosmo--purge-file asm-clang)
|
||
(save-buffer)
|
||
(setq cosmo--assembly-root root)
|
||
(setq cosmo--assembly-pending (cons asm-gcc asm-clang))
|
||
(let ((errormsg (shell-command-to-string (format "touch %s" file))))
|
||
(when (not (equal "" errormsg))
|
||
(error errormsg)))
|
||
(revert-buffer :ignore-auto :noconfirm)
|
||
(compile compile-command))))))
|
||
|
||
(defun cosmo-assembly (arg)
|
||
(interactive "P")
|
||
(setq arg (or arg 2))
|
||
;; -ffast-math -funsafe-math-optimizations -fsched2-use-superblocks -fjump-tables
|
||
(cond ((not (eq 0 (logand 8 arg)))
|
||
(cosmo--assembly (setq arg (logand (lognot 8)))
|
||
"SILENT=0 COPTS='-Os'"))
|
||
(t (cosmo--assembly arg "SILENT=0 COPTS='-Os' TARGET_ARCH='-march=znver2 -mdispatch-scheduler' CPPFLAGS='-DSTACK_FRAME_UNLIMITED'"))))
|
||
|
||
(defun cosmo-assembly-native (arg)
|
||
(interactive "P")
|
||
(setq arg (or arg 3))
|
||
(cond ((not (eq 0 (logand 8 arg)))
|
||
(cosmo--assembly
|
||
(setq arg (logand (lognot 8)))
|
||
"SILENT=0 CCFLAGS=--verbose COPTS='$(IEEE_MATH)' CPPFLAGS='-DSTACK_FRAME_UNLIMITED' TARGET_ARCH='-march=k8'")) ;; znver2
|
||
(t
|
||
(cosmo--assembly
|
||
arg
|
||
"SILENT=0 CCFLAGS=--verbose COPTS='$(MATHEMATICAL) -O3' CPPFLAGS='-DSTACK_FRAME_UNLIMITED' TARGET_ARCH='-march=k8'")))) ;; znver2
|
||
|
||
(defun cosmo-assembly-icelake (arg)
|
||
(interactive "P")
|
||
(setq arg (or arg 3))
|
||
(cond ((not (eq 0 (logand 8 arg)))
|
||
(cosmo--assembly
|
||
(setq arg (logand (lognot 8)))
|
||
"SILENT=0 CCFLAGS=--verbose COPTS='$(MATHEMATICAL) -O3' CPPFLAGS='-DSTACK_FRAME_UNLIMITED' TARGET_ARCH='-march=icelake-client'"))
|
||
(t
|
||
(cosmo--assembly
|
||
arg
|
||
"SILENT=0 CCFLAGS=--verbose COPTS='$(MATHEMATICAL) -O3' CPPFLAGS='-DSTACK_FRAME_UNLIMITED' TARGET_ARCH='-march=icelake-client'"))))
|
||
|
||
(defun cosmo-assembly-balanced (arg)
|
||
(interactive "P")
|
||
(cosmo--assembly (or arg 5) "CFLAGS='-O2 -ftrapv' CPPFLAGS='-DSTACK_FRAME_UNLIMITED' SILENT=0"))
|
||
|
||
(defun cosmo-mca (arg)
|
||
(interactive "P")
|
||
(let (code
|
||
delete
|
||
cleanup
|
||
(inhibit-message t)
|
||
(inhibit-read-only t)
|
||
(term (getenv "TERM"))
|
||
(prog (executable-find "llvm-mca-10"))
|
||
(buf1 (get-buffer-create "*mca*"))
|
||
(buf2 (generate-new-buffer "*mca*")))
|
||
(setenv "TERM" "xterm-256color")
|
||
(setq cleanup
|
||
(lambda ()
|
||
(setenv term)
|
||
(kill-buffer buf2)
|
||
(when delete (delete-file delete))))
|
||
(condition-case exc
|
||
(progn
|
||
(if (not (buffer-modified-p))
|
||
(setq code (buffer-file-name))
|
||
(setq code (make-temp-file "mca.s"))
|
||
(write-region nil nil code)
|
||
(setq delete code))
|
||
(with-current-buffer buf2
|
||
(insert "\n")
|
||
(setq rc (call-process prog nil t nil
|
||
"-mcpu=skylake"
|
||
"-mtriple=x86_64-pc-linux-gnu"
|
||
"--bottleneck-analysis"
|
||
"-instruction-info"
|
||
"-iterations=8"
|
||
"-all-stats"
|
||
"-all-views"
|
||
"-timeline"
|
||
code)))
|
||
(with-current-buffer buf1
|
||
(replace-buffer-contents buf2)
|
||
(if (eq rc 0)
|
||
(fundamental-mode)
|
||
(compilation-mode))
|
||
(xterm-color-colorize-buffer)
|
||
(display-buffer (current-buffer))))
|
||
('error
|
||
(funcall cleanup)
|
||
(error exc)))
|
||
(funcall cleanup)))
|
||
|
||
(defun cosmo-assemble-hook ()
|
||
(add-to-list 'compilation-finish-functions
|
||
'cosmo--assembly-compilation-finished)
|
||
(local-set-key (kbd "C-c C-a") 'cosmo-assembly)
|
||
(local-set-key (kbd "C-c C-b") 'cosmo-assembly-balanced)
|
||
(local-set-key (kbd "C-c C-n") 'cosmo-assembly-native)
|
||
(local-set-key (kbd "C-c C-i") 'cosmo-assembly-icelake))
|
||
|
||
(defun cosmo-mca-hook ()
|
||
;; (local-set-key (kbd "C-c C-h") 'cosmo-mca)
|
||
)
|
||
|
||
(progn
|
||
(add-hook 'asm-mode-hook 'cosmo-mca-hook)
|
||
(add-hook 'makefile-mode-hook 'cosmo-assemble-hook)
|
||
(add-hook 'asm-mode-hook 'cosmo-assemble-hook)
|
||
(add-hook 'ld-script-mode-hook 'cosmo-assemble-hook)
|
||
(add-hook 'dired-mode-hook 'cosmo-assemble-hook)
|
||
(add-hook 'c-mode-common-hook 'cosmo-assemble-hook)
|
||
(add-hook 'fortran-mode-hook 'cosmo-assemble-hook)
|
||
(add-hook 'protobuf-mode-hook 'cosmo-assemble-hook))
|
||
|
||
|
||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
;; Run buffer.
|
||
;; C-c C-r Run
|
||
;; M-1 C-c C-r Run w/ MODE=tiny
|
||
;; M-2 C-c C-r Run w/ MODE=opt
|
||
;; M-3 C-c C-r Run w/ MODE=rel
|
||
;; M-4 C-c C-r Run w/ MODE=dbg
|
||
;; M-5 C-c C-r Run w/ MODE=""
|
||
|
||
(defun cosmo-run (arg)
|
||
(interactive "P")
|
||
(let* ((this (or (buffer-file-name) dired-directory))
|
||
(proj (locate-dominating-file this "Makefile"))
|
||
(root (or proj default-directory))
|
||
(file (file-relative-name this root)))
|
||
(when root
|
||
(let ((default-directory root))
|
||
(save-buffer)
|
||
(cond ((file-executable-p file)
|
||
(compile (if (cosmo-contains "/" file)
|
||
file
|
||
(format "./%s" file))))
|
||
((memq major-mode '(c-mode c++-mode asm-mode fortran-mode))
|
||
(let* ((mode (cosmo--make-mode arg))
|
||
(compile-command (cosmo--compile-command this root 'run mode "" "")))
|
||
(compile compile-command)))
|
||
((eq major-mode 'sh-mode)
|
||
(compile (format "sh %s" file)))
|
||
((eq major-mode 'python-mode)
|
||
(compile (format "python %s" file)))
|
||
('t
|
||
(error "cosmo-run: unknown major mode")))))))
|
||
|
||
(progn
|
||
(define-key asm-mode-map (kbd "C-c C-r") 'cosmo-run)
|
||
(define-key c-mode-base-map (kbd "C-c C-r") 'cosmo-run)
|
||
(define-key fortran-mode-map (kbd "C-c C-r") 'cosmo-run)
|
||
(define-key sh-mode-map (kbd "C-c C-r") 'cosmo-run)
|
||
(define-key python-mode-map (kbd "C-c C-r") 'cosmo-run))
|
||
|
||
|
||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
;; Debug buffer.
|
||
;; C-c C-d Run in GDB/GUD
|
||
;; M-1 C-c C-d Run in GDB/GUD w/ MODE=tiny
|
||
;; M-2 C-c C-d Run in GDB/GUD w/ MODE=opt
|
||
;; M-3 C-c C-d Run in GDB/GUD w/ MODE=rel
|
||
;; M-4 C-c C-d Run in GDB/GUD w/ MODE=dbg
|
||
;; M-5 C-c C-d Run in GDB/GUD w/ MODE=""
|
||
|
||
(defun cosmo-debug (arg)
|
||
(interactive "P")
|
||
(let* ((this (or (buffer-file-name) dired-directory))
|
||
(root (locate-dominating-file this "Makefile")))
|
||
(when root
|
||
(let* ((mode (cosmo--make-mode arg "dbg"))
|
||
(name (file-relative-name this root))
|
||
(next (file-name-sans-extension name))
|
||
(exec (format "o/%s/%s.com.dbg" mode next))
|
||
(default-directory root)
|
||
(compile-command (cosmo--compile-command this root nil mode "" "")))
|
||
(compile compile-command)
|
||
(gdb (format "gdb -q -nh -i=mi %s -ex run" exec))))))
|
||
|
||
(progn
|
||
(define-key asm-mode-map (kbd "C-c C-d") 'cosmo-debug)
|
||
(define-key c-mode-base-map (kbd "C-c C-d") 'cosmo-debug))
|
||
|
||
|
||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
;; C-c C-t Toggle buffer between source file and unit test file.
|
||
|
||
(defun cosmo-toggle-buddy ()
|
||
(interactive)
|
||
(let* ((this (or (buffer-file-name) dired-directory))
|
||
(root (locate-dominating-file this "Makefile")))
|
||
(when root
|
||
(let* ((name (file-relative-name this root))
|
||
(dir (file-name-directory this))
|
||
(pkgname (file-name-nondirectory (substring dir 0 -1)))
|
||
(dots (file-relative-name root dir))
|
||
(notest (cosmo-file-name-sans-extensions
|
||
(cosmo-replace "_test" "" (cosmo-lchop "test/" name))))
|
||
(buddy
|
||
(cond ((and (cosmo-startswith "test/" dir)
|
||
(cosmo-endswith "/test.mk" name))
|
||
(message (format "%s/%s.mk" (substring dir 5) pkgname))
|
||
(format "%s/%s.mk" (substring dir 5) pkgname))
|
||
((cosmo-startswith "test/" name)
|
||
(cosmo-first-that
|
||
'file-exists-p
|
||
(list (concat dots notest ".s")
|
||
(concat dots notest ".S")
|
||
(concat dots notest ".f")
|
||
(concat dots notest ".F")
|
||
(concat dots notest ".c")
|
||
(concat dots notest ".cc")
|
||
(concat dots notest ".rl")
|
||
(concat dots notest ".ncabi.c")
|
||
(concat dots notest ".hookabi.c")
|
||
(concat dots notest ".h"))))
|
||
(t
|
||
(format "%stest/%s_test.c"
|
||
dots (cosmo-file-name-sans-extensions name))))))
|
||
(when buddy
|
||
(find-file buddy))))))
|
||
|
||
(progn
|
||
(global-set-key (kbd "C-c C-t") 'cosmo-toggle-buddy))
|
||
|
||
|
||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
;; C-c C-h Add Include Line
|
||
|
||
(defun cosmo-add-include ()
|
||
(interactive)
|
||
(let* ((no-whine t)
|
||
(tag-file "HTAGS")
|
||
(this (buffer-name))
|
||
(case-fold-search nil)
|
||
(search (thing-at-point 'symbol))
|
||
(buffer (find-file-noselect (format "%s/%s"
|
||
(locate-dominating-file
|
||
this tag-file)
|
||
tag-file)
|
||
no-whine))
|
||
(header (with-current-buffer buffer
|
||
(revert-buffer :ignore-auto :noconfirm)
|
||
(save-excursion
|
||
(goto-char 0)
|
||
(when (re-search-forward
|
||
(concat "\177" search "\001") nil t)
|
||
(when (re-search-backward "\f\n\\([^,]*\\)," nil t)
|
||
(match-string 1))))))
|
||
(root (locate-dominating-file this "Makefile"))
|
||
(name (file-relative-name this root)))
|
||
(when header
|
||
(when (not (equal header name))
|
||
(save-excursion
|
||
(goto-char 0)
|
||
(re-search-forward "#include" nil t)
|
||
(re-search-forward "^$")
|
||
(re-search-backward "#include" nil t)
|
||
(beginning-of-line)
|
||
(insert (concat "#include \"" header "\"\n"))))
|
||
(message header))))
|
||
|
||
(progn
|
||
(define-key asm-mode-map (kbd "C-c C-h") 'cosmo-add-include)
|
||
(define-key c-mode-base-map (kbd "C-c C-h") 'cosmo-add-include))
|
||
|
||
|
||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
;; C-c C-o Show Optimization Report
|
||
|
||
(defun cosmo-show-optinfo (arg)
|
||
(interactive "P")
|
||
(let* ((mode (cosmo--make-mode arg "opt"))
|
||
(this (or (buffer-file-name) dired-directory))
|
||
(root (locate-dominating-file this "Makefile")))
|
||
(when root
|
||
(let* ((name (file-relative-name this root))
|
||
(buddy
|
||
(format "%s/o/%s/%s.optinfo.gz"
|
||
root mode (cosmo-file-name-sans-extensions name))))
|
||
(when buddy
|
||
(find-file buddy))))))
|
||
(defun cosmo-lisp-is-the-worst-this-is-so-tiring ()
|
||
(define-key c-mode-base-map (kbd "C-c C-o") 'cosmo-show-optinfo))
|
||
(add-hook 'c-mode-common-hook 'cosmo-lisp-is-the-worst-this-is-so-tiring)
|
||
|
||
|
||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
;; Cosmopolitan Extended Language Keyword Definitions
|
||
|
||
(defun cosmo-c-keywords-hook ()
|
||
(font-lock-add-keywords
|
||
nil `((,cosmo-c-keywords-regex . font-lock-keyword-face)
|
||
(,cosmo-c-builtins-regex . font-lock-builtin-face)
|
||
(,cosmo-platform-constants-regex . font-lock-builtin-face)
|
||
(,cosmo-cpp-constants-regex . font-lock-constant-face)
|
||
(,cosmo-c-constants-regex . font-lock-constant-face)
|
||
(,cosmo-c-types-regex . font-lock-type-face))))
|
||
|
||
(defun cosmo-asm-keywords-hook ()
|
||
(font-lock-add-keywords
|
||
nil `((,cosmo-cpp-constants-regex . font-lock-constant-face)
|
||
(,cosmo-platform-constants-regex . font-lock-constant-face))))
|
||
|
||
(add-hook 'c-mode-common-hook 'cosmo-c-keywords-hook)
|
||
(add-hook 'asm-mode-hook 'cosmo-asm-keywords-hook)
|
||
|
||
|
||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
;; Symbol naming convention conversion
|
||
|
||
;; e.g. STARTF_USESHOWWINDOW -> kNtStartfUseshowwindow
|
||
(defun cosmo--ms-to-google-const (s)
|
||
(declare (pure t) (side-effect-free t))
|
||
(let ((d (downcase (substring s 1))))
|
||
(cosmo-replace
|
||
"kNtNt" "kNt"
|
||
(concat
|
||
"kNt"
|
||
(substring s 0 1)
|
||
(replace-regexp-in-string
|
||
"_\\([A-Za-z]\\)"
|
||
(lambda (m)
|
||
(upcase (match-string 1 m)))
|
||
d)))))
|
||
|
||
;; e.g. kNtStartfUseshowwindow -> STARTF_USESHOWWINDOW
|
||
(defun cosmo--google-to-ms-const (s)
|
||
(declare (pure t) (side-effect-free t))
|
||
(upcase (replace-regexp-in-string
|
||
"\\(.\\)\\([A-Z]\\)"
|
||
(lambda (m)
|
||
(upcase (concat
|
||
(match-string 1 m) "_"
|
||
(match-string 2 m))))
|
||
(substring s 3)
|
||
t)))
|
||
|
||
(defun cosmo-toggle-ms-const ()
|
||
(interactive)
|
||
(let* ((case-fold-search nil)
|
||
(bounds (if (use-region-p)
|
||
(cons (region-beginning) (region-end))
|
||
(bounds-of-thing-at-point 'symbol)))
|
||
(text (buffer-substring-no-properties (car bounds) (cdr bounds))))
|
||
(when bounds
|
||
(let ((fn (if (or (cosmo-contains "_" text)
|
||
(equal text (upcase text)))
|
||
'cosmo--ms-to-google-const
|
||
'cosmo--google-to-ms-const)))
|
||
(delete-region (car bounds) (cdr bounds))
|
||
(insert (funcall fn text))))))
|
||
|
||
;; (define-key c-mode-base-map (kbd "C-c C-l") 'cosmo-toggle-ms-const)
|
||
|
||
|
||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
;; CP/M EOF for the lulz
|
||
|
||
(defun cosmo-before-save ()
|
||
(cond ((memq major-mode '(c-mode asm-mode))
|
||
(set (make-local-variable 'require-final-newline)
|
||
(not (equal (buffer-substring-no-properties
|
||
(- (point-max) 1) (point-max))
|
||
"\x1a"))))))
|
||
|
||
(add-hook 'before-save-hook 'cosmo-before-save)
|
||
|
||
(provide 'cosmo-stuff)
|
||
|
||
;;; cosmo-stuff.el ends here
|