(require 'json)
(defvar eaw-src-home (concat (getenv "HOME") "/src"))
(defvar eaw-build-map nil)
(defun eaw-expand-src-dir (dir)
(expand-file-name (concat eaw-src-home "/" dir "/")))
(defun eaw-find-likely-proj-root ()
(or
(eaw-find-file-down-heirarchy ".gitignore" eaw-src-home)
(eaw-find-file-up-heirarchy "compile_commands.json" eaw-src-home)
(concat eaw-src-home "/")))
(defvar eaw-proj-map (make-sparse-keymap))
(define-key global-map (kbd "C-x g") eaw-proj-map)
(defvar eaw-proj-rootdir "")
(defvar eaw-proj-change-hook nil)
(defun eaw-proj-go (proj)
(interactive
(list (read-directory-name "proj root: "
(eaw-find-likely-proj-root)
(eaw-find-likely-proj-root)
t)))
(if (not (unless (string= (expand-file-name proj) eaw-proj-rootdir)))
(let* ((projdir (expand-file-name (concat proj "/")))
(nonsrc (substring projdir (length (expand-file-name (concat eaw-src-home "/"))) -1))
dirname)
(message "switching to %s" projdir)
(setq eaw-proj-rootdir projdir)
(run-hooks 'eaw-proj-change-hook))))
(define-key eaw-proj-map "g" 'eaw-proj-go)
(defun eaw-proj-vc-go ()
(interactive)
(let ((default-directory eaw-proj-rootdir))
(magit-status)))
(define-key eaw-proj-map "j" 'eaw-proj-vc-go)
(defun eaw-find-dir-in-build-map (curdir)
(let (found)
(dolist (mapval eaw-build-map)
(unless found
(let ((mapdir (eaw-expand-src-dir (car mapval))))
(if (or (string= curdir mapdir)
(and (> (length curdir) (length mapdir))
(string= (substring curdir (length mapdir) -1) mapdir)))
(setq found (cdr mapval))))))
found))
(defun eaw-find-likely-build-list ()
(let ((found nil))
(setq found (eaw-find-dir-in-build-map eaw-proj-rootdir))
(unless found (setq found (eaw-find-dir-in-build-map (eaw-find-likely-proj-root))))
(cond
((stringp found) (eaw-expand-src-dir found))
((listp found) (mapcar 'eaw-expand-src-dir found))
(t default-directory))))
(defun eaw-find-likely-build-dir ()
"Return the likely build directory for the given project. First
consult `eaw-proj-rootdir', then `eaw-find-likely-proj-root'.
Consult each against `eaw-build-map'. If the build map is nil, or
they aren't in the build map, just return `default-directory'. If
the build map is non-nil, then car is a source directory and cdr
is either a build directory (string) or a list of build
directories."
(let ((fulldirs (eaw-find-likely-build-list)))
(if fulldirs
(if (stringp fulldirs)
fulldirs
(reduce '(lambda (a b)
(if (string-prefix-p (file-truename b) (file-truename default-directory)) b a))
fulldirs))
eaw-proj-rootdir)))
(defvar eaw-compile-list
'(("build.ninja" . "ninja -j 4 %s")
("Makefile" . "make -j 4 %s")))
(require 'cl)
(defun eaw-compile-likely-dir (&optional tgt)
(interactive)
(let ((default-directory (eaw-find-likely-build-dir))
(target (or tgt "")))
(dolist (elt eaw-compile-list)
(when (file-exists-p (car elt))
(compile
(cond
((stringp (cdr elt)) (format (cdr elt) target))
((functionp (cdr elt)) (funcall (cdr elt) target))
(t (error))))
(return)))))
(define-key eaw-proj-map "b" 'eaw-compile-likely-dir)
(defun eaw-clean-likely-dir ()
(interactive)
(eaw-compile-likely-dir "clean"))
(define-key eaw-proj-map "c" 'eaw-clean-likely-dir)
(defun eaw-proj-whereami ()
(interactive)
(if eaw-proj-rootdir (message eaw-proj-rootdir) (message "No project currently selected")))
(define-key eaw-proj-map "w" 'eaw-proj-whereami)
(defun eaw-project-shell ()
(interactive)
(let* ((default-directory eaw-proj-rootdir)
(projname (file-name-nondirectory (directory-file-name default-directory))))
(shell
(concat "*shell-" projname "*"))))
(define-key eaw-proj-map "z" 'eaw-project-shell)
(defun eaw-project-eshell ()
(interactive)
(let* ((default-directory eaw-proj-rootdir)
(projname (file-name-nondirectory (directory-file-name default-directory)))
(eshell-buffer-name (concat "*eshell-" projname "*"))
(orig-esh-hist-fn (default-value 'eshell-history-file-name))
(new-esh-hist-fn (expand-file-name (concat "history-" projname) eshell-directory-name)))
(if (get-buffer eshell-buffer-name)
(pop-to-buffer eshell-buffer-name))
(setq-default eshell-history-file-name new-esh-hist-fn)
(eshell)
(setq-default eshell-history-file-name orig-esh-hist-fn)))
(define-key eaw-proj-map "e" 'eaw-project-eshell)
(defun eaw-ios-sdk-ver (&optional platform)
(interactive)
(let ((choices
(seq-map
(lambda (elt) (alist-get 'canonicalName elt))
(seq-filter
(lambda (elt) (string= (or platform "iphonesimulator") (alist-get 'platform elt)))
(json-read-from-string (shell-command-to-string "xcodebuild -showsdks -json"))))))
(cond
((= 0 (length choices)) (error "No iOS SDK versions available"))
((= 1 (length choices)) (car choices))
(t (ido-completing-read "iOS SDK version: " choices)))))
(defun eaw-ios-sim-ver ()
(interactive)
(let ((choices
(seq-map
(lambda (elt) (alist-get 'version elt))
(seq-filter
(lambda (elt) (string-prefix-p "iOS " (alist-get 'name elt)))
(alist-get
'runtimes
(json-read-from-string (shell-command-to-string "xcrun simctl list runtimes available --json")))))))
(cond
((= 0 (length choices)) (error "No iOS Simulators available"))
((= 1 (length choices)) (car choices))
(t (ido-completing-read "iOS Simulator version: " choices)))))
(setq eaw-ios-sim-dev "iPhone 12 Pro")
(defun eaw-choose-ios-sim-dev ()
(interactive)
(let ((choices
(seq-map
(lambda (elt) (alist-get 'name elt))
(seq-mapcat
'cdr
(alist-get
'devices
(json-read-from-string (shell-command-to-string "xcrun simctl list devices iOS --json")))))))
(setq eaw-ios-sim-dev (ido-completing-read "iOS Simulator device: " choices nil t nil nil eaw-ios-sim-dev))
(shell-command "xcrun simctl shutdown booted")))
(setq eaw-ios-workspace nil
eaw-ios-scheme nil
eaw-ios-project nil)
(defun eaw-ios-build-cmd-base ()
(concat "xcodebuild "
(if eaw-ios-project
(concat "-project " eaw-ios-project " ")
(concat
"-derivedDataPath DerivedData "
"-workspace " eaw-ios-workspace " "
"-scheme " eaw-ios-scheme " "
))
"-configuration Debug "
"-sdk " (eaw-ios-sdk-ver) " "
"-destination 'platform=iOS Simulator,name=" eaw-ios-sim-dev ",OS=" (eaw-ios-sim-ver) "' "
"-parallelizeTargets -jobs 6 "))
(defun eaw-ios-build (&optional target)
(interactive)
(concat
(eaw-ios-build-cmd-base)
target
(if (executable-find "xcpretty")
" | xcpretty --no-color --no-utf"
"-quiet ")))
(defun eaw-ios-find-workspace ()
(interactive)
(let* ((default-directory eaw-proj-rootdir)
(choices (sort
(cond
((file-expand-wildcards "*.xcworkspace"))
((file-expand-wildcards "*.xcodeproj"))
((file-expand-wildcards "*/*.xcworkspace"))
((file-expand-wildcards "*/*.xcodeproj")))
'string<))
(choice
(cond
((= 1 (length choices)) (car choices))
((< 1 (length choices)) (ido-completing-read "XCode Workspace/Project file: " choices)))))
(if (and choice (string-match-p "xcodeproj\\'" choice))
(setq eaw-ios-workspace nil
eaw-ios-scheme nil
eaw-ios-project choice)
(setq eaw-ios-workspace choice
eaw-ios-project nil))
(unless (or (not choice) (assoc choice eaw-compile-list))
(add-to-list 'eaw-compile-list `(,choice . eaw-ios-build)))))
(defun eaw-ios-xcode ()
(interactive)
(if eaw-ios-workspace
(shell-command (concat "open " eaw-proj-rootdir eaw-ios-workspace))))
(if (executable-find "xcodebuild")
(progn
(define-key eaw-proj-map "d" 'eaw-choose-ios-sim-dev)
(define-key eaw-proj-map "x" 'eaw-ios-xcode)
(add-hook 'eaw-proj-change-hook 'eaw-ios-find-workspace)))
(defun my-c-initialization-hook ()
(define-key c-mode-base-map "\C-m" 'c-context-line-break)
(define-key c-mode-base-map (kbd "C-c C-c") 'comment-or-uncomment-region))
(add-hook 'c-initialization-hook 'my-c-initialization-hook)
(defconst my-c-style
'((c-block-comment-prefix . "* ")
(c-cleanup-list . (brace-else-brace
brace-elseif-brace
brace-catch-brace
defun-close-semi
list-close-comma
scope-operator
comment-close-slash))
(c-basic-offset . 4)
(c-offsets-alist . ((inline-open . 0)
(statement . 0)
(statement-cont . +)
(statement-block-intro . +)
(statement-case-intro . +)
(statement-case-open . 0)
(substatement . +)
(substatement-open . 0)
(member-init-intro . *)
(member-init-cont . c-lineup-multi-inher)
(access-label . -)
(case-label . 0)
(label . /)
(friend . 0)
(extern-lang-open . 0)
(inextern-lang . 0)
(extern-lang-close . 0)
(namespace-open . 0)
(innamespace . 0)
(namespace-close . 0)
(knr-argdecl . 0)
(knr-argdecl-intro . +)))
(c-hanging-braces-alist . ((brace-list-open)
(brace-list-close)
(brace-entry-open)
(statement-cont)
(substatement-open after)
(block-close)
(defun-close)
(extern-lang-open after)
(namespace-open after)
(module-open after)
(composition-open after)
(inexpr-class-open after)
(inexpr-class-close before)))
(fill-column . 80)
(c-comment-only-line-offset . 0))
"My C Programming Style")
(c-add-style "sane" my-c-style)
(defun eaw-cpp-header ()
(let ((name (or buffer-file-name (buffer-name))))
(and name
(string-match "\\.h\\'" name)
(re-search-forward "\\W\\(class\\|template\\|namespace\\)\\W" nil t))))
(add-to-list 'magic-mode-alist '(eaw-cpp-header . c++-mode))
(defun eaw-objc-header ()
(let ((name (or buffer-file-name (buffer-name))))
(and name
(string-match "\\.h\\'" name)
(re-search-forward "\\W@\\(interface\\|property\\|end\\)\\W" nil t))))
(add-to-list 'magic-mode-alist '(eaw-objc-header . objc-mode))
(add-to-list 'auto-mode-alist '("\\.mm\\'" . objc-mode))
(if (require 'grep nil t)
(progn
(add-to-list 'grep-files-aliases '("mm" . "*.m *.mm *.cc *.cxx *.cpp *.C *.CC *.c++"))
(add-to-list 'grep-files-aliases '("mmhh" . "*.m *.mm *.cc *.cxx *.cpp *.C *.CC *.c++ *.hxx *.hpp *.[Hh] *.HH *.h++"))))
(defvar eaw-anything-c-source-objc-headline
'((name . "Objective-C Headline")
(headline "^[-+@]\\|^#pragma mark")))
(if (require 'anything nil t)
(progn
(require 'anything-config)
(defun eaw-objc-headline ()
(interactive)
(let ((anything-candidate-number-limit 500))
(anything-other-buffer '(eaw-anything-c-source-objc-headline)
"*ObjC Headline*")))
(global-set-key (kbd "C-c o") 'eaw-objc-headline)))
(setenv "CTAGS" "----langmap=ObjectiveC:.m.h")
(defun my-c-mode-common-hook ()
(c-set-style "sane")
(c-toggle-electric-state 1)
(c-toggle-auto-newline 1)
(c-toggle-hungry-state -1)
(if (fboundp 'c-subword-mode)
(c-subword-mode 1)
(subword-mode 1))
(if (fboundp 'hs-minor-mode)
(hs-minor-mode 1))
(c-toggle-syntactic-indentation 1)
(setq c-tab-always-indent t)
(setq c-electric-pound-behavior '(alignleft))
)
(add-hook 'c-mode-common-hook 'my-c-mode-common-hook)
(if (require 'js2-mode nil t)
(progn
(add-to-list 'auto-mode-alist '("\\.js$" . js2-mode))
(add-hook 'js2-mode-hook '(lambda () (whitespace-mode 1)))
(setq js2-highlight-level 3
js2-bounce-indent-p t)
(define-key js2-mode-map (kbd "C-m") 'newline-and-indent)
(defun eaw-setup-js2-externs ()
(when (> (buffer-size) 0)
(let ((btext (replace-regexp-in-string
": *true" " "
(replace-regexp-in-string "[\n\t ]+" " " (buffer-substring-no-properties 1 (buffer-size)) t t))))
(mapc (apply-partially 'add-to-list 'js2-additional-externs)
(split-string
(if (string-match "/\\* *global *\\(.*?\\) *\\*/" btext) (match-string-no-properties 1 btext) "")
" *, *" t))
)))
(add-hook 'js2-post-parse-callbacks 'eaw-setup-js2-externs)
(setq js2-global-externs '("require" "module"))))
(defun eaw-json-cleanup (start end)
"Pretty-print JSON in region"
(interactive (list (region-beginning) (region-end)))
(shell-command-on-region start end "python -m json.tool" nil t))
(defun eaw-js-cleanup (start end)
"Pretty-print JS in region"
(interactive (list (region-beginning) (region-end)))
(shell-command-on-region start end
(concat "java -jar " (getenv "HOME") "/var/compiler.jar "
"--formatting PRETTY_PRINT --compilation_level WHITESPACE_ONLY --language_in ECMASCRIPT6") nil t))
(defun eaw-url-cleanup ()
"Pretty-print percent-encoded URL param in region"
(interactive)
(let* ((start (region-beginning))
(end (region-end))
(encoded (buffer-substring start end)))
(delete-region (min start end) (max start end))
(insert (url-unhex-string encoded))))
(defun eaw-url-encode ()
"Pretty-print percent-encoded URL param in region"
(interactive)
(let* ((start (region-beginning))
(end (region-end))
(decoded (buffer-substring start end)))
(delete-region (min start end) (max start end))
(insert (url-hexify-string decoded))))
(setq nxml-slash-auto-complete-flag t)
(add-hook 'nxml-mode-hook '(lambda () (define-key nxml-mode-map (kbd "C-c C-c") 'comment-or-uncomment-region)))
(autoload 'groovy-mode "groovy-mode" "Major mode for editing Groovy code." t)
(add-to-list 'auto-mode-alist '("\.groovy$" . groovy-mode))
(add-to-list 'interpreter-mode-alist '("groovy" . groovy-mode))
(add-hook 'groovy-mode-hook
'(lambda ()
(require 'groovy-electric)
(groovy-electric-mode)))
(defun eaw-c4z-dec ()
(interactive)
(shell-command-on-region
(point-min) (point-max)
(concat "openssl smime -decrypt -inkey " (getenv "HOME") "/etc/c4/privatekey.pem -inform der")
t t))
(defun eaw-c4i-dec ()
(interactive)
(shell-command-on-region
(point) (mark)
(concat "openssl aes-256-ctr -d -a -iv 00000000000000000000000000000001 -K 7db208c0699b14b46ef81b97f39afc9868dd158f1636f7f43866dfe55f19f498")
t t))
(defun eaw-project-try-vc (orig-fun dir)
(let ((ptvc-dir (apply orig-fun (list dir))))
(if (and ptvc-dir (string= (expand-file-name dir) (expand-file-name (cdr ptvc-dir))))
ptvc-dir
(eaw-project-try-vc orig-fun (cdr ptvc-dir)))))
(if (require 'project nil t)
(progn
(setq project-list-file (locate-user-emacs-file "var/projects"))
(advice-add 'project-try-vc :around #'eaw-project-try-vc)
(require 'eglot nil t)))
(defun eaw-ios-cc-update ()
"Updates the compile_commands.json project information for iOS"
(interactive)
(let ((default-directory eaw-proj-rootdir))
(compile
(concat (eaw-ios-build-cmd-base) " clean build "
" | "
"xcpretty --no-color --no-utf -r json-compilation-database -o "
eaw-proj-rootdir "compile_commands.json"
" && perl -pi -e 's/ -gmodules / /g' " eaw-proj-rootdir "compile_commands.json"))))
(if (and (executable-find "xcodebuild")
(executable-find "xcpretty"))
(define-key eaw-proj-map "u" 'eaw-ios-cc-update))
(defadvice flymake-master-make-header-init (after eaw-flymake-after-master)
(if (string= flymake-mode-line-e-w "!")
(flymake-report-fatal-status "NOMASTER" "no master file for header")))
(ad-activate 'flymake-master-make-header-init)
(defun eaw-cleanup-flymake-timers ()
(dolist (tmr timer-list)
(if (and (timer--args tmr)
(nth 0 (timer--args tmr))
(bufferp (nth 0 (timer--args tmr)))
(or (not (buffer-live-p (nth 0 (timer--args tmr))))
(with-current-buffer (nth 0 (timer--args tmr)) buffer-read-only)))
(cancel-timer tmr))))
(run-with-timer (* 30 60) (* 30 60) 'eaw-cleanup-flymake-timers)
(setq compilation-context-lines 1)
(setq compilation-scroll-output t)
(setenv "ANT_ARGS" "-emacs")
(autoload 'cmake-mode "cmake-mode")
(add-to-list 'auto-mode-alist '("CMakeLists\\.txt\\'" . cmake-mode))
(add-to-list 'auto-mode-alist '("\\.cmake\\'" . cmake-mode))
(setq gdb-many-windows t
gdb-max-frames 120)
(require 'lldb nil t)
(provide 'ew-devel)