Initial commit
This commit is contained in:
commit
d88fb3194f
27 changed files with 2752 additions and 0 deletions
1026
+bindings.el
Normal file
1026
+bindings.el
Normal file
File diff suppressed because it is too large
Load diff
119
+commands.el
Normal file
119
+commands.el
Normal file
|
@ -0,0 +1,119 @@
|
|||
;;; private/grfn/+commands.el -*- lexical-binding: t; -*-
|
||||
|
||||
(defalias 'ex! 'evil-ex-define-cmd)
|
||||
|
||||
(defun delete-file-and-buffer ()
|
||||
"Kill the current buffer and deletes the file it is visiting."
|
||||
(interactive)
|
||||
(let ((filename (buffer-file-name)))
|
||||
(when filename
|
||||
(if (vc-backend filename)
|
||||
(vc-delete-file filename)
|
||||
(progn
|
||||
(delete-file filename)
|
||||
(message "Deleted file %s" filename)
|
||||
(kill-buffer))))))
|
||||
|
||||
;;; Commands defined elsewhere
|
||||
;;(ex! "al[ign]" #'+evil:align)
|
||||
;;(ex! "g[lobal]" #'+evil:global)
|
||||
|
||||
;;; Custom commands
|
||||
;; Editing
|
||||
(ex! "@" #'+evil:macro-on-all-lines) ; TODO Test me
|
||||
(ex! "al[ign]" #'+evil:align)
|
||||
(ex! "enhtml" #'+web:encode-html-entities)
|
||||
(ex! "dehtml" #'+web:decode-html-entities)
|
||||
(ex! "mc" #'+evil:mc)
|
||||
(ex! "iedit" #'evil-multiedit-ex-match)
|
||||
(ex! "na[rrow]" #'+evil:narrow-buffer)
|
||||
(ex! "retab" #'+evil:retab)
|
||||
|
||||
;; External resources
|
||||
;; TODO (ex! "db" #'doom:db)
|
||||
;; TODO (ex! "dbu[se]" #'doom:db-select)
|
||||
;; TODO (ex! "go[ogle]" #'doom:google-search)
|
||||
(ex! "lo[okup]" #'+jump:online)
|
||||
(ex! "dash" #'+lookup:dash)
|
||||
(ex! "dd" #'+lookup:devdocs)
|
||||
(ex! "http" #'httpd-start) ; start http server
|
||||
(ex! "repl" #'+eval:repl) ; invoke or send to repl
|
||||
;; TODO (ex! "rx" 'doom:regex) ; open re-builder
|
||||
(ex! "sh[ell]" #'+eshell:run)
|
||||
(ex! "t[mux]" #'+tmux:run) ; send to tmux
|
||||
(ex! "tcd" #'+tmux:cd-here) ; cd to default-directory in tmux
|
||||
(ex! "x" #'doom/open-project-scratch-buffer)
|
||||
|
||||
;; GIT
|
||||
(ex! "gist" #'+gist:send) ; send current buffer/region to gist
|
||||
(ex! "gistl" #'+gist:list) ; list gists by user
|
||||
(ex! "gbrowse" #'+vcs/git-browse) ; show file in github/gitlab
|
||||
(ex! "gissues" #'+vcs/git-browse-issues) ; show github issues
|
||||
(ex! "git" #'magit-status) ; open magit status window
|
||||
(ex! "gstage" #'magit-stage)
|
||||
(ex! "gunstage" #'magit-unstage)
|
||||
(ex! "gblame" #'magit-blame)
|
||||
(ex! "grevert" #'git-gutter:revert-hunk)
|
||||
|
||||
;; Dealing with buffers
|
||||
(ex! "clean[up]" #'doom/cleanup-buffers)
|
||||
(ex! "k[ill]" #'doom/kill-this-buffer)
|
||||
(ex! "k[ill]all" #'+hlissner:kill-all-buffers)
|
||||
(ex! "k[ill]m" #'+hlissner:kill-matching-buffers)
|
||||
(ex! "k[ill]o" #'doom/kill-other-buffers)
|
||||
(ex! "l[ast]" #'doom/popup-restore)
|
||||
(ex! "m[sg]" #'view-echo-area-messages)
|
||||
(ex! "pop[up]" #'doom/popup-this-buffer)
|
||||
|
||||
;; Project navigation
|
||||
(ex! "a" #'projectile-toggle-between-implementation-and-test)
|
||||
(ex! "as" #'projectile-find-implementation-or-test-other-window)
|
||||
(ex! "av" #'projectile-find-implementation-or-test-other-window)
|
||||
(ex! "cd" #'+hlissner:cd)
|
||||
(cond ((featurep! :completion ivy)
|
||||
(ex! "ag" #'+ivy:ag)
|
||||
(ex! "agc[wd]" #'+ivy:ag-cwd)
|
||||
(ex! "rg" #'+ivy:rg)
|
||||
(ex! "rgc[wd]" #'+ivy:rg-cwd)
|
||||
(ex! "sw[iper]" #'+ivy:swiper)
|
||||
(ex! "todo" #'+ivy:todo))
|
||||
((featurep! :completion helm)
|
||||
(ex! "ag" #'+helm:ag)
|
||||
(ex! "agc[wd]" #'+helm:ag-cwd)
|
||||
(ex! "rg" #'+helm:rg)
|
||||
(ex! "rgc[wd]" #'+helm:rg-cwd)
|
||||
(ex! "sw[oop]" #'+helm:swoop)
|
||||
(ex! "todo" #'+helm:todo)))
|
||||
|
||||
;; Project tools
|
||||
(ex! "build" #'+eval/build)
|
||||
(ex! "debug" #'+debug/run)
|
||||
(ex! "er[rors]" #'flycheck-list-errors)
|
||||
|
||||
;; File operations
|
||||
(ex! "cp" #'+evil:copy-this-file)
|
||||
(ex! "mv" #'+evil:move-this-file)
|
||||
(ex! "rm" #'+evil:delete-this-file)
|
||||
|
||||
;; Sessions/tabs
|
||||
(ex! "sclear" #'+workspace/kill-session)
|
||||
(ex! "sl[oad]" #'+workspace:load-session)
|
||||
(ex! "ss[ave]" #'+workspace:save-session)
|
||||
(ex! "tabcl[ose]" #'+workspace:delete)
|
||||
(ex! "tabclear" #'doom/kill-all-buffers)
|
||||
(ex! "tabl[ast]" #'+workspace/switch-to-last)
|
||||
(ex! "tabload" #'+workspace:load)
|
||||
(ex! "tabn[ew]" #'+workspace:new)
|
||||
(ex! "tabn[ext]" #'+workspace:switch-next)
|
||||
(ex! "tabp[rev]" #'+workspace:switch-previous)
|
||||
(ex! "tabr[ename]" #'+workspace:rename)
|
||||
(ex! "tabs" #'+workspace/display)
|
||||
(ex! "tabsave" #'+workspace:save)
|
||||
|
||||
;; Org-mode
|
||||
(ex! "cap" #'+org-capture/dwim)
|
||||
|
||||
;; Elixir
|
||||
(add-hook! elixir-mode
|
||||
(ex! "AV" #'alchemist-project-toggle-file-and-tests-other-window)
|
||||
(ex! "A" #'alchemist-project-toggle-file-and-tests))
|
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
.authinfo.gpg
|
||||
+private.el
|
37
autoload/evil.el
Normal file
37
autoload/evil.el
Normal file
|
@ -0,0 +1,37 @@
|
|||
;;; /autoload/evil.el -*- lexical-binding: t; -*-
|
||||
;;;###if (featurep! :feature evil)
|
||||
|
||||
;;;###autoload (autoload '+hlissner:multi-next-line "/autoload/evil" nil t)
|
||||
(evil-define-motion +hlissner:multi-next-line (count)
|
||||
"Move down 6 lines."
|
||||
:type line
|
||||
(let ((line-move-visual (or visual-line-mode (derived-mode-p 'text-mode))))
|
||||
(evil-line-move (* 6 (or count 1)))))
|
||||
|
||||
;;;###autoload (autoload '+hlissner:multi-previous-line "/autoload/evil" nil t)
|
||||
(evil-define-motion +hlissner:multi-previous-line (count)
|
||||
"Move up 6 lines."
|
||||
:type line
|
||||
(let ((line-move-visual (or visual-line-mode (derived-mode-p 'text-mode))))
|
||||
(evil-line-move (- (* 6 (or count 1))))))
|
||||
|
||||
;;;###autoload (autoload '+hlissner:cd "/autoload/evil" nil t)
|
||||
(evil-define-command +hlissner:cd ()
|
||||
"Change `default-directory' with `cd'."
|
||||
(interactive "<f>")
|
||||
(cd input))
|
||||
|
||||
;;;###autoload (autoload '+hlissner:kill-all-buffers "/autoload/evil" nil t)
|
||||
(evil-define-command +hlissner:kill-all-buffers (&optional bang)
|
||||
"Kill all buffers. If BANG, kill current session too."
|
||||
(interactive "<!>")
|
||||
(if bang
|
||||
(+workspace/kill-session)
|
||||
(doom/kill-all-buffers)))
|
||||
|
||||
;;;###autoload (autoload '+hlissner:kill-matching-buffers "/autoload/evil" nil t)
|
||||
(evil-define-command +hlissner:kill-matching-buffers (&optional bang pattern)
|
||||
"Kill all buffers matching PATTERN regexp. If BANG, only match project
|
||||
buffers."
|
||||
(interactive "<a>")
|
||||
(doom/kill-matching-buffers pattern bang))
|
53
autoload/hlissner.el
Normal file
53
autoload/hlissner.el
Normal file
|
@ -0,0 +1,53 @@
|
|||
;;; autoload/hlissner.el -*- lexical-binding: t; -*-
|
||||
|
||||
;;;###autoload
|
||||
(defun +hlissner/install-snippets ()
|
||||
"Install my snippets from https://github.com/hlissner/emacs-snippets into
|
||||
private/hlissner/snippets."
|
||||
(interactive)
|
||||
(doom-fetch :github "hlissner/emacs-snippets"
|
||||
(expand-file-name "snippets" (doom-module-path :private 'hlissner))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +hlissner/yank-buffer-filename ()
|
||||
"Copy the current buffer's path to the kill ring."
|
||||
(interactive)
|
||||
(if-let* ((filename (or buffer-file-name (bound-and-true-p list-buffers-directory))))
|
||||
(message (kill-new (abbreviate-file-name filename)))
|
||||
(error "Couldn't find filename in current buffer")))
|
||||
|
||||
(defmacro +hlissner-def-finder! (name dir)
|
||||
"Define a pair of find-file and browse functions."
|
||||
`(progn
|
||||
(defun ,(intern (format "+hlissner/find-in-%s" name)) ()
|
||||
(interactive)
|
||||
(let ((default-directory ,dir)
|
||||
projectile-project-name
|
||||
projectile-require-project-root
|
||||
projectile-cached-buffer-file-name
|
||||
projectile-cached-project-root)
|
||||
(call-interactively (command-remapping #'projectile-find-file))))
|
||||
(defun ,(intern (format "+hlissner/browse-%s" name)) ()
|
||||
(interactive)
|
||||
(let ((default-directory ,dir))
|
||||
(call-interactively (command-remapping #'find-file))))))
|
||||
|
||||
;;;###autoload (autoload '+hlissner/find-in-templates "autoload/hlissner" nil t)
|
||||
;;;###autoload (autoload '+hlissner/browse-templates "autoload/hlissner" nil t)
|
||||
(+hlissner-def-finder! templates +file-templates-dir)
|
||||
|
||||
;;;###autoload (autoload '+hlissner/find-in-snippets "autoload/hlissner" nil t)
|
||||
;;;###autoload (autoload '+hlissner/browse-snippets "autoload/hlissner" nil t)
|
||||
(+hlissner-def-finder! snippets +hlissner-snippets-dir)
|
||||
|
||||
;;;###autoload (autoload '+hlissner/find-in-dotfiles "autoload/hlissner" nil t)
|
||||
;;;###autoload (autoload '+hlissner/browse-dotfiles "autoload/hlissner" nil t)
|
||||
(+hlissner-def-finder! dotfiles (expand-file-name ".dotfiles" "~"))
|
||||
|
||||
;;;###autoload (autoload '+hlissner/find-in-emacsd "autoload/hlissner" nil t)
|
||||
;;;###autoload (autoload '+hlissner/browse-emacsd "autoload/hlissner" nil t)
|
||||
(+hlissner-def-finder! emacsd doom-emacs-dir)
|
||||
|
||||
;;;###autoload (autoload '+hlissner/find-in-notes "autoload/hlissner" nil t)
|
||||
;;;###autoload (autoload '+hlissner/browse-notes "autoload/hlissner" nil t)
|
||||
(+hlissner-def-finder! notes +org-dir)
|
409
config.el
Normal file
409
config.el
Normal file
|
@ -0,0 +1,409 @@
|
|||
;;; private/grfn/config.el -*- lexical-binding: t; -*-
|
||||
|
||||
(defvar +grfn-dir (file-name-directory load-file-name))
|
||||
(defvar +grfn-snippets-dir (expand-file-name "snippets/" +grfn-dir))
|
||||
|
||||
;;
|
||||
(when (featurep! :feature evil)
|
||||
(load! +bindings)
|
||||
(load! +commands))
|
||||
|
||||
(load! +private)
|
||||
|
||||
(require 'dash)
|
||||
|
||||
|
||||
;;
|
||||
;; Global config
|
||||
;;
|
||||
|
||||
(setq +doom-modeline-buffer-file-name-style 'relative-to-project)
|
||||
|
||||
;;
|
||||
;; Modules
|
||||
;;
|
||||
|
||||
(after! smartparens
|
||||
;; Auto-close more conservatively and expand braces on RET
|
||||
(let ((unless-list '(sp-point-before-word-p
|
||||
sp-point-after-word-p
|
||||
sp-point-before-same-p)))
|
||||
(sp-pair "'" nil :unless unless-list)
|
||||
(sp-pair "\"" nil :unless unless-list))
|
||||
(sp-pair "{" nil :post-handlers '(("||\n[i]" "RET") ("| " " "))
|
||||
:unless '(sp-point-before-word-p sp-point-before-same-p))
|
||||
(sp-pair "(" nil :post-handlers '(("||\n[i]" "RET") ("| " " "))
|
||||
:unless '(sp-point-before-word-p sp-point-before-same-p))
|
||||
(sp-pair "[" nil :post-handlers '(("| " " "))
|
||||
:unless '(sp-point-before-word-p sp-point-before-same-p)))
|
||||
|
||||
;; feature/evil
|
||||
(after! evil-mc
|
||||
;; Make evil-mc resume its cursors when I switch to insert mode
|
||||
(add-hook! 'evil-mc-before-cursors-created
|
||||
(add-hook 'evil-insert-state-entry-hook #'evil-mc-resume-cursors nil t))
|
||||
(add-hook! 'evil-mc-after-cursors-deleted
|
||||
(remove-hook 'evil-insert-state-entry-hook #'evil-mc-resume-cursors t)))
|
||||
|
||||
;; feature/snippets
|
||||
(after! yasnippet
|
||||
;; Don't use default snippets, use mine.
|
||||
(setq yas-snippet-dirs
|
||||
(append (list '+grfn-snippets-dir)
|
||||
(delq 'yas-installed-snippets-dir yas-snippet-dirs))))
|
||||
|
||||
;; completion/helm
|
||||
(after! helm
|
||||
;; Hide header lines in helm. I don't like them
|
||||
(set-face-attribute 'helm-source-header nil :height 0.1))
|
||||
|
||||
(after! company
|
||||
(setq company-idle-delay 0.2
|
||||
company-minimum-prefix-length 1))
|
||||
|
||||
(setq +doom-modeline-height 10)
|
||||
|
||||
;; lang/org
|
||||
;; (after! org-bullets
|
||||
;; ;; The standard unicode characters are usually misaligned depending on the
|
||||
;; ;; font. This bugs me. Personally, markdown #-marks for headlines are more
|
||||
;; ;; elegant, so we use those.
|
||||
;; (setq org-bullets-bullet-list '("#")))
|
||||
|
||||
;; (defmacro faces! (mode &rest forms)
|
||||
;; (let ((hook-name (-> mode symbol-name (concat "-hook"))))
|
||||
;; (if-let ((hook-sym (intern-soft hook-name)))
|
||||
;; `(add-hook! ,hook-sym
|
||||
;; (message "HELLO I AM MACRO TIME")
|
||||
;; ,@(->
|
||||
;; forms
|
||||
;; (seq-partition 2)
|
||||
;; (->> (seq-map
|
||||
;; (lambda (pair)
|
||||
;; (let ((face (car pair))
|
||||
;; (color (cadr pair)))
|
||||
;; `(set-face-foreground ,face ,color)))))))
|
||||
;; (warn "Hook name %s (for mode %s) does not exist as symbol!"
|
||||
;; (hook-name)
|
||||
;; (symbol-name mode)))))
|
||||
|
||||
(def-package! org-clubhouse)
|
||||
|
||||
(setq solarized-use-variable-pitch nil
|
||||
solarized-scale-org-headlines nil)
|
||||
|
||||
; (require 'doom-themes)
|
||||
|
||||
;; Should really figure out which of these is correct, eventually
|
||||
|
||||
(after! doom-theme
|
||||
(set-face-foreground 'font-lock-doc-face +solarized-s-base1)
|
||||
(set-face-foreground 'org-block +solarized-s-base00)
|
||||
(set-face-foreground 'slack-message-output-header +solarized-s-base01)
|
||||
(set-face-attribute 'slack-message-output-header nil :underline nil)
|
||||
(set-face-attribute 'slack-message-output-text nil :height 1.0)
|
||||
)
|
||||
|
||||
(after! solarized-theme
|
||||
(set-face-foreground 'font-lock-doc-face +solarized-s-base1)
|
||||
(set-face-foreground 'org-block +solarized-s-base00)
|
||||
|
||||
(set-face-foreground 'slack-message-output-header +solarized-s-base01)
|
||||
(set-face-attribute 'slack-message-output-header nil :underline nil)
|
||||
(set-face-attribute 'slack-message-output-text nil :height 1.0)
|
||||
)
|
||||
|
||||
(after! slack
|
||||
(set-face-foreground 'slack-message-output-header +solarized-s-base01)
|
||||
(set-face-attribute 'slack-message-output-header nil :underline nil)
|
||||
(set-face-attribute 'slack-message-output-text nil :height 1.0))
|
||||
|
||||
(after! evil
|
||||
(setq evil-shift-width 2))
|
||||
|
||||
(after! org
|
||||
(setq
|
||||
org-directory (expand-file-name "~/notes")
|
||||
+org-dir (expand-file-name "~/notes")
|
||||
org-default-notes-file (concat org-directory "/inbox.org")
|
||||
+org-default-todo-file (concat org-directory "/inbox.org")
|
||||
org-agenda-files (list (expand-file-name "~/notes"))
|
||||
org-refile-targets '((org-agenda-files :maxlevel . 1))
|
||||
org-file-apps `((auto-mode . emacs)
|
||||
(,(rx (or (and "." (optional "x") (optional "htm") (optional "l") buffer-end)
|
||||
(and buffer-start "http" (optional "s") "://")))
|
||||
. "firefox %s")
|
||||
(,(rx ".pdf" buffer-end) . "apvlv %s")
|
||||
(,(rx "." (or "png"
|
||||
"jpg"
|
||||
"jpeg"
|
||||
"gif"
|
||||
"tif"
|
||||
"tiff")
|
||||
buffer-end)
|
||||
. "feh %s"))
|
||||
org-log-done 'time
|
||||
org-archive-location "~/notes/trash::* From %s"
|
||||
org-cycle-separator-lines 2
|
||||
org-hidden-keywords '(title)
|
||||
org-tags-column -130
|
||||
org-ellipsis "⤵"
|
||||
org-capture-templates
|
||||
'(("t" "Todo" entry
|
||||
(file+headline +org-default-todo-file "Inbox")
|
||||
"* TODO %?\n%i" :prepend t :kill-buffer t)
|
||||
|
||||
("n" "Notes" entry
|
||||
(file+headline +org-default-notes-file "Inbox")
|
||||
"* %u %?\n%i" :prepend t :kill-buffer t))
|
||||
org-deadline-warning-days 1
|
||||
org-agenda-skip-scheduled-if-deadline-is-shown 't)
|
||||
(set-face-foreground 'org-block +solarized-s-base00)
|
||||
(add-hook! org-mode
|
||||
(add-hook! evil-normal-state-entry-hook
|
||||
#'org-align-all-tags))
|
||||
(setf (alist-get 'file org-link-frame-setup) 'find-file-other-window)
|
||||
(set-face-foreground 'org-block +solarized-s-base00))
|
||||
|
||||
(after! magit
|
||||
(setq git-commit-summary-max-length 50)
|
||||
(require 'magit-gh-pulls)
|
||||
(add-hook 'magit-mode-hook 'turn-on-magit-gh-pulls))
|
||||
|
||||
(comment
|
||||
|
||||
(string-match-p "(?!foo).*" "bar")
|
||||
)
|
||||
|
||||
(after! ivy
|
||||
(setq ivy-re-builders-alist
|
||||
'((t . ivy--regex-fuzzy))))
|
||||
|
||||
(setq doom-font (font-spec :family "Meslo LGSDZ Nerd Font" :size 14)
|
||||
doom-big-font (font-spec :family "Meslo LGSDZ Nerd Font" :size 19)
|
||||
doom-variable-pitch-font (font-spec :family "DejaVu Sans")
|
||||
doom-unicode-font (font-spec :family "Meslo LG S DZ"))
|
||||
|
||||
(add-hook 'before-save-hook 'delete-trailing-whitespace)
|
||||
|
||||
(after! paxedit
|
||||
(add-hook! emacs-lisp-mode #'paxedit-mode)
|
||||
(add-hook! clojure-mode #'paxedit-mode))
|
||||
|
||||
(require 'haskell)
|
||||
|
||||
(let ((m-symbols
|
||||
'(("`mappend`" . "⊕")
|
||||
("<>" . "⊕"))))
|
||||
(dolist (item m-symbols) (add-to-list 'haskell-font-lock-symbols-alist item)))
|
||||
|
||||
(setq haskell-font-lock-symbols t)
|
||||
|
||||
|
||||
(add-hook! haskell-mode
|
||||
(intero-mode)
|
||||
(flycheck-add-next-checker
|
||||
'intero
|
||||
'haskell-hlint)
|
||||
(set-fill-column 100))
|
||||
|
||||
;; (load! org-clubhouse)
|
||||
(add-hook! org-mode #'org-clubhouse-mode)
|
||||
|
||||
(load! slack-snippets)
|
||||
|
||||
(after! magit
|
||||
(require 'evil-magit)
|
||||
(require 'magithub)
|
||||
)
|
||||
|
||||
; (require 'auth-password-store)
|
||||
; (auth-pass-enable)
|
||||
(auth-source-pass-enable)
|
||||
|
||||
(require 'fill-column-indicator)
|
||||
;;; * Column Marker
|
||||
(defun sanityinc/fci-enabled-p () (symbol-value 'fci-mode))
|
||||
|
||||
(defvar sanityinc/fci-mode-suppressed nil)
|
||||
(make-variable-buffer-local 'sanityinc/fci-mode-suppressed)
|
||||
|
||||
(defadvice popup-create (before suppress-fci-mode activate)
|
||||
"Suspend fci-mode while popups are visible"
|
||||
(let ((fci-enabled (sanityinc/fci-enabled-p)))
|
||||
(when fci-enabled
|
||||
(setq sanityinc/fci-mode-suppressed fci-enabled)
|
||||
(turn-off-fci-mode))))
|
||||
|
||||
(defadvice popup-delete (after restore-fci-mode activate)
|
||||
"Restore fci-mode when all popups have closed"
|
||||
(when (and sanityinc/fci-mode-suppressed
|
||||
(null popup-instances))
|
||||
(setq sanityinc/fci-mode-suppressed nil)
|
||||
(turn-on-fci-mode)))
|
||||
|
||||
|
||||
;; https://github.com/alpaker/Fill-Column-Indicator/issues/67#issuecomment-195611974
|
||||
(add-hook 'prog-mode-hook #'fci-mode)
|
||||
(after! fill-column-indicator
|
||||
(add-hook 'prog-mode-hook #'fci-mode)
|
||||
(defvar eos/fci-disabled nil)
|
||||
(make-variable-buffer-local 'eos/fci-disabled)
|
||||
|
||||
;; Add a hook that disables fci if enabled when the window changes and it
|
||||
;; isn't wide enough to display it.
|
||||
(defun eos/maybe-disable-fci ()
|
||||
(interactive)
|
||||
;; Disable FCI if necessary
|
||||
(when (and fci-mode
|
||||
(< (window-width) (or fci-rule-column fill-column)))
|
||||
(fci-mode -1)
|
||||
(setq-local eos/fci-disabled t))
|
||||
;; Enable FCI if necessary
|
||||
(when (and eos/fci-disabled
|
||||
(eq fci-mode nil)
|
||||
(> (window-width) (or fci-rule-column fill-column)))
|
||||
(fci-mode 1)
|
||||
(setq-local eos/fci-disabled nil)))
|
||||
|
||||
(defun eos/add-fci-disabling-hook ()
|
||||
(interactive)
|
||||
(add-hook 'window-configuration-change-hook
|
||||
#'eos/maybe-disable-fci))
|
||||
|
||||
(add-hook 'prog-mode-hook #'eos/add-fci-disabling-hook))
|
||||
|
||||
|
||||
;;; Javascript
|
||||
|
||||
(setq js-indent-level 2)
|
||||
|
||||
(require 'prettier-js)
|
||||
(after! prettier-js
|
||||
(add-hook! rjsx-mode #'prettier-js-mode)
|
||||
(add-hook! js2-mode #'prettier-js-mode)
|
||||
(add-hook! json-mode #'prettier-js-mode)
|
||||
(add-hook! css-mode #'prettier-js-mode))
|
||||
|
||||
(require 'flycheck-flow)
|
||||
(with-eval-after-load 'flycheck
|
||||
(flycheck-add-mode 'javascript-flow 'rjsx-mode)
|
||||
(flycheck-add-mode 'javascript-flow 'flow-minor-mode)
|
||||
(flycheck-add-mode 'javascript-eslint 'flow-minor-mode)
|
||||
(flycheck-add-next-checker 'javascript-flow 'javascript-eslint))
|
||||
|
||||
(require 'flow-minor-mode)
|
||||
|
||||
|
||||
;; Auto-format Haskell on save, with a combination of hindent + brittany
|
||||
|
||||
(define-minor-mode brittany-haskell-mode
|
||||
:init-value nil
|
||||
:group 'haskell
|
||||
:lighter "Brittany-Haskell"
|
||||
:keymap '()
|
||||
)
|
||||
|
||||
|
||||
(defun urbint/format-haskell-source ()
|
||||
(interactive)
|
||||
(let ((output-buffer (generate-new-buffer "brittany-out"))
|
||||
(config-file-path
|
||||
(concat (string-trim
|
||||
(shell-command-to-string "stack path --project-root"))
|
||||
"/brittany.yaml")))
|
||||
(when (= 0 (call-process-region
|
||||
(point-min) (point-max)
|
||||
"stack"
|
||||
nil output-buffer nil
|
||||
"exec" "--" "brittany" "--config-file" config-file-path))
|
||||
(let ((pt (point))
|
||||
(wst (window-start))
|
||||
(formatted-source (with-current-buffer output-buffer
|
||||
(buffer-string))))
|
||||
(erase-buffer)
|
||||
(insert formatted-source)
|
||||
(goto-char pt)
|
||||
(set-window-start nil wst)))))
|
||||
|
||||
(add-hook
|
||||
'before-save-hook
|
||||
(lambda ()
|
||||
(when (and (eq major-mode 'haskell-mode)
|
||||
(bound-and-true-p brittany-haskell-mode))
|
||||
(urbint/format-haskell-source))))
|
||||
|
||||
(require 'slack)
|
||||
(setq slack-buffer-emojify 't
|
||||
slack-prefer-current-team 't)
|
||||
(require 'alert)
|
||||
(setq alert-default-style 'libnotify)
|
||||
|
||||
;; (setq slack-buffer-function #'switch-to-buffer)
|
||||
|
||||
(setq projectile-test-suffix-function
|
||||
(lambda (project-type)
|
||||
(case project-type
|
||||
('haskell-stack "Test")
|
||||
('npm ".test")
|
||||
(otherwise (projectile-test-suffix project-type)))))
|
||||
|
||||
(defun magit-commit-wip ()
|
||||
(interactive)
|
||||
(magit-commit "-m wip"))
|
||||
|
||||
;; (magit-define-popup-action 'magit-commit-popup
|
||||
;; ?w "WIP" 'magit-commit-wip)
|
||||
|
||||
;; (defun grfn/split-window-more-sensibly (&optional window)
|
||||
;; (let ((window (or window (selected-window))))
|
||||
;; (or (and (window-splittable-p window)
|
||||
;; ;; Split window vertically.
|
||||
;; (with-selected-window window
|
||||
;; (split-window-right)))
|
||||
;; (and (window-splittable-p window t)
|
||||
;; ;; Split window horizontally.
|
||||
;; (with-selected-window window
|
||||
;; (split-window-right)))
|
||||
;; (and (eq window (frame-root-window (window-frame window)))
|
||||
;; (not (window-minibuffer-p window))
|
||||
;; ;; If WINDOW is the only window on its frame and is not the
|
||||
;; ;; minibuffer window, try to split it vertically disregarding
|
||||
;; ;; the value of `split-height-threshold'.
|
||||
;; (let ((split-height-threshold 0))
|
||||
;; (when (window-splittable-p window)
|
||||
;; (with-selected-window window
|
||||
;; (split-window-below))))))))
|
||||
|
||||
;; (def-package! lsp-mode
|
||||
;; :after (:any haskell-mode)
|
||||
;; :config
|
||||
;; (lsp-mode))
|
||||
|
||||
;; (def-package! lsp-ui
|
||||
;; :after lsp-mode
|
||||
;; :config
|
||||
;; (setq lsp-ui-flycheck-enable t)
|
||||
;; (setq imenu-auto-rescan t)
|
||||
;; (set-face-background 'lsp-ui-doc-background +solarized-s-base2)
|
||||
;; (set-face-background 'lsp-face-highlight-read +solarized-s-base2)
|
||||
;; (set-face-background 'lsp-face-highlight-orite +solarized-s-base2)
|
||||
;; :hook
|
||||
;; (lsp-mode . lsp-ui-mode)
|
||||
;; (lsp-ui-mode . flycheck-mode))
|
||||
|
||||
;; (def-package! company-lsp
|
||||
;; :after (lsp-mode lsp-ui)
|
||||
;; :config
|
||||
;; (setq company-backends '(company-lsp))
|
||||
;; (setq company-lsp-async t))
|
||||
|
||||
;; (def-package! lsp-haskell
|
||||
;; :after (lsp-mode lsp-ui haskell-mode)
|
||||
;; :hook
|
||||
;; (haskell-mode . lsp-haskell-enable))
|
||||
|
||||
(def-package! evil-magit
|
||||
:after (magit))
|
||||
|
||||
(def-package! writeroom-mode)
|
247
init.el
Normal file
247
init.el
Normal file
|
@ -0,0 +1,247 @@
|
|||
;;; private/grfn/init.el -*- lexical-binding: t; -*-
|
||||
|
||||
;; An extra measure to prevent the flash of unstyled mode-line while Emacs is
|
||||
;; booting up (when Doom is byte-compiled).
|
||||
(setq-default mode-line-format nil)
|
||||
|
||||
|
||||
;; I've swapped these keys on my keyboard
|
||||
(setq x-super-keysym 'alt
|
||||
x-alt-keysym 'meta)
|
||||
|
||||
(setq user-mail-address "root@gws.fyi"
|
||||
user-full-name "Griffin Smith")
|
||||
|
||||
(add-hook! doom-big-font-mode
|
||||
(setq +doom-modeline-height (if doom-big-font-mode 37 29)))
|
||||
|
||||
; (def-package-hook! doom-themes :disable)
|
||||
|
||||
(after! rust
|
||||
(setq rust-format-on-save t))
|
||||
|
||||
; (defconst rust-src-path
|
||||
; (-> "/Users/griffin/.cargo/bin/rustc --print sysroot"
|
||||
; shell-command-to-string
|
||||
; string-trim
|
||||
; (concat "/lib/rustlib/src/rust/src")))
|
||||
;
|
||||
; (setenv "RUST_SRC_PATH" rust-src-path)
|
||||
;
|
||||
; (after! racer
|
||||
; (setq racer-rust-src-path rust-src-path))
|
||||
;
|
||||
(add-hook! rust-mode
|
||||
(flycheck-rust-setup)
|
||||
(flycheck-mode)
|
||||
(racer-mode)
|
||||
(cargo-minor-mode))
|
||||
|
||||
(add-hook! elixir-mode
|
||||
(require 'flycheck-credo)
|
||||
(setq flycheck-elixir-credo-strict t)
|
||||
(flycheck-credo-setup)
|
||||
|
||||
(require 'flycheck-mix) (flycheck-mix-setup)
|
||||
|
||||
(require 'flycheck-dialyxir) (flycheck-dialyxir-setup)
|
||||
|
||||
(flycheck-mode))
|
||||
|
||||
(setq exec-path (append exec-path '("/Users/griffin/.cargo/bin")))
|
||||
|
||||
(after! cargo
|
||||
(setq cargo-process--custom-path-to-bin "/Users/griffin/.cargo/bin/cargo"))
|
||||
|
||||
(setq +solarized-s-base03 "#002b36"
|
||||
+solarized-s-base02 "#073642"
|
||||
;; emphasized content
|
||||
+solarized-s-base01 "#586e75"
|
||||
;; primary content
|
||||
+solarized-s-base00 "#657b83"
|
||||
+solarized-s-base0 "#839496"
|
||||
;; comments
|
||||
+solarized-s-base1 "#93a1a1"
|
||||
;; background highlight light
|
||||
+solarized-s-base2 "#eee8d5"
|
||||
;; background light
|
||||
+solarized-s-base3 "#fdf6e3"
|
||||
|
||||
;; Solarized accented colors
|
||||
+solarized-yellow "#b58900"
|
||||
+solarized-orange "#cb4b16"
|
||||
+solarized-red "#dc322f"
|
||||
+solarized-magenta "#d33682"
|
||||
+solarized-violet "#6c71c4"
|
||||
+solarized-blue "#268bd2"
|
||||
+solarized-cyan "#2aa198"
|
||||
+solarized-green "#859900"
|
||||
|
||||
;; Darker and lighter accented colors
|
||||
;; Only use these in exceptional circumstances!
|
||||
+solarized-yellow-d "#7B6000"
|
||||
+solarized-yellow-l "#DEB542"
|
||||
+solarized-orange-d "#8B2C02"
|
||||
+solarized-orange-l "#F2804F"
|
||||
+solarized-red-d "#990A1B"
|
||||
+solarized-red-l "#FF6E64"
|
||||
+solarized-magenta-d "#93115C"
|
||||
+solarized-magenta-l "#F771AC"
|
||||
+solarized-violet-d "#3F4D91"
|
||||
+solarized-violet-l "#9EA0E5"
|
||||
+solarized-blue-d "#00629D"
|
||||
+solarized-blue-l "#69B7F0"
|
||||
+solarized-cyan-d "#00736F"
|
||||
+solarized-cyan-l "#69CABF"
|
||||
+solarized-green-d "#546E00"
|
||||
+solarized-green-l "#B4C342")
|
||||
|
||||
(defadvice load-theme (after theme-set-overrides activate)
|
||||
(dolist (theme-settings theme-overrides)
|
||||
(let ((theme (car theme-settings))
|
||||
(faces (cadr theme-settings)))
|
||||
(if (member theme custom-enabled-themes)
|
||||
(dolist (face faces)
|
||||
(custom-theme-set-faces theme face))))))
|
||||
|
||||
(defcustom theme-overrides nil
|
||||
"Association list of override faces to set for different custom themes.")
|
||||
|
||||
(defun alist-set (alist-symbol key value)
|
||||
"Set VALUE of a KEY in ALIST-SYMBOL."
|
||||
(set alist-symbol (cons (list key value) (assq-delete-all key (eval alist-symbol)))))
|
||||
|
||||
(alist-set 'theme-overrides 'grfn-solarized-light
|
||||
`((font-lock-doc-face ((t (:foreground ,+solarized-s-base1))))
|
||||
(font-lock-preprocessor-face ((t (:foreground ,+solarized-red))))
|
||||
(font-lock-keyword-face ((t (:foreground ,+solarized-green))))
|
||||
|
||||
(elixir-attribute-face ((t (:foreground ,+solarized-blue))))
|
||||
(elixir-atom-face ((t (:foreground ,+solarized-cyan))))
|
||||
(linum ((t (:background ,+solarized-s-base2 :foreground ,+solarized-s-base1))))
|
||||
(line-number ((t (:background ,+solarized-s-base2 :foreground ,+solarized-s-base1))))
|
||||
|
||||
(haskell-operator-face ((t (:foreground ,+solarized-green))))
|
||||
(haskell-keyword-face ((t (:foreground ,+solarized-cyan))))))
|
||||
|
||||
(add-to-list 'custom-theme-load-path "~/.doom.d/themes")
|
||||
(load-theme 'grfn-solarized-light t)
|
||||
|
||||
(defface haskell-import-face `((t (:foreground ,+solarized-magenta))) "")
|
||||
|
||||
(setq doom-theme 'grfn-solarized-light)
|
||||
; (setq doom-theme 'doom-solarized-light)
|
||||
|
||||
(add-hook! doom-post-init
|
||||
(set-face-attribute 'bold nil :weight 'ultra-light)
|
||||
(set-face-bold-p 'bold nil))
|
||||
|
||||
(defun rx-words (&rest words)
|
||||
(rx-to-string
|
||||
`(and symbol-start (group (or ,@words)) symbol-end)))
|
||||
|
||||
(font-lock-add-keywords
|
||||
'elixir-mode
|
||||
`((,(rx-words "def"
|
||||
"defp"
|
||||
"test"
|
||||
"describe"
|
||||
"property"
|
||||
"defrecord"
|
||||
"defmodule"
|
||||
"defstruct"
|
||||
"defdelegate"
|
||||
"defprotocol"
|
||||
"defimpl"
|
||||
"use"
|
||||
"import"
|
||||
"alias"
|
||||
"require"
|
||||
"assert"
|
||||
"refute"
|
||||
"assert_raise")
|
||||
.
|
||||
'font-lock-preprocessor-face)))
|
||||
|
||||
(font-lock-add-keywords
|
||||
'elixir-mode
|
||||
`((,(rx-words "def"
|
||||
"defp"
|
||||
"test"
|
||||
"describe"
|
||||
"property"
|
||||
"defrecord"
|
||||
"defmodule"
|
||||
"defstruct"
|
||||
"defdelegate"
|
||||
"use"
|
||||
"import"
|
||||
"alias"
|
||||
"require"
|
||||
"assert"
|
||||
"refute"
|
||||
"assert_raise")
|
||||
.
|
||||
'font-lock-preprocessor-face)))
|
||||
|
||||
(font-lock-add-keywords
|
||||
'haskell-mode
|
||||
`((,(rx-words "import") . 'haskell-import-face)))
|
||||
|
||||
;; (font-lock-add-keywords
|
||||
;; 'haskell-mode
|
||||
;; `((,(rx "-- |") . 'haskell-keyword-face)))
|
||||
|
||||
;;; * Column Marker
|
||||
(defun sanityinc/fci-enabled-p () (symbol-value 'fci-mode))
|
||||
|
||||
(defvar sanityinc/fci-mode-suppressed nil)
|
||||
(make-variable-buffer-local 'sanityinc/fci-mode-suppressed)
|
||||
|
||||
(defadvice popup-create (before suppress-fci-mode activate)
|
||||
"Suspend fci-mode while popups are visible"
|
||||
(let ((fci-enabled (sanityinc/fci-enabled-p)))
|
||||
(when fci-enabled
|
||||
(setq sanityinc/fci-mode-suppressed fci-enabled)
|
||||
(turn-off-fci-mode))))
|
||||
|
||||
(defadvice popup-delete (after restore-fci-mode activate)
|
||||
"Restore fci-mode when all popups have closed"
|
||||
(when (and sanityinc/fci-mode-suppressed
|
||||
(null popup-instances))
|
||||
(setq sanityinc/fci-mode-suppressed nil)
|
||||
(turn-on-fci-mode)))
|
||||
|
||||
|
||||
;; https://github.com/alpaker/Fill-Column-Indicator/issues/67#issuecomment-195611974
|
||||
(after! fill-column-indicator
|
||||
(add-hook 'prog-mode-hook #'fci-mode)
|
||||
(defvar eos/fci-disabled nil)
|
||||
(make-variable-buffer-local 'eos/fci-disabled)
|
||||
|
||||
;; Add a hook that disables fci if enabled when the window changes and it
|
||||
;; isn't wide enough to display it.
|
||||
(defun eos/maybe-disable-fci ()
|
||||
(interactive)
|
||||
;; Disable FCI if necessary
|
||||
(when (and fci-mode
|
||||
(< (window-width) (or fci-rule-column fill-column)))
|
||||
(fci-mode -1)
|
||||
(setq-local eos/fci-disabled t))
|
||||
;; Enable FCI if necessary
|
||||
(when (and eos/fci-disabled
|
||||
(eq fci-mode nil)
|
||||
(> (window-width) (or fci-rule-column fill-column)))
|
||||
(fci-mode 1)
|
||||
(setq-local eos/fci-disabled nil)))
|
||||
|
||||
(defun eos/add-fci-disabling-hook ()
|
||||
(interactive)
|
||||
(add-hook 'window-configuration-change-hook
|
||||
#'eos/maybe-disable-fci))
|
||||
|
||||
(add-hook 'prog-mode-hook #'eos/add-fci-disabling-hook))
|
||||
|
||||
; (require 'haskell-prettify)
|
||||
|
||||
;; (add-hook 'haskell-mode-hook #'haskell-prettify-enable)
|
58
packages.el
Normal file
58
packages.el
Normal file
|
@ -0,0 +1,58 @@
|
|||
;; -*- no-byte-compile: t; -*-
|
||||
;;; private/grfn/packages.el
|
||||
|
||||
;; Editor
|
||||
(package! solarized-theme)
|
||||
(package! fill-column-indicator)
|
||||
(package! flx)
|
||||
(package! general
|
||||
:recipe (general
|
||||
:fetcher github
|
||||
:repo "noctuid/general.el"))
|
||||
(package! org-clubhouse
|
||||
:recipe (org-clubhouse
|
||||
:fetcher file
|
||||
:path "~/code/urb/org-clubhouse"))
|
||||
(package! fill-column-indicator)
|
||||
(package! writeroom-mode)
|
||||
(package! dash)
|
||||
|
||||
;; Slack etc
|
||||
(package! slack)
|
||||
(package! alert)
|
||||
|
||||
;; Git
|
||||
(package! evil-magit)
|
||||
(package! magithub)
|
||||
(package! magit-gh-pulls)
|
||||
(package! marshal)
|
||||
; (package! auth-password-store)
|
||||
|
||||
;; Elisp
|
||||
(package! dash)
|
||||
(package! dash-functional)
|
||||
(package! s)
|
||||
(package! request)
|
||||
|
||||
;; Haskell
|
||||
(package! lsp-mode)
|
||||
(package! lsp-ui :recipe (:fetcher github :repo "emacs-lsp/lsp-ui"))
|
||||
(package! lsp-haskell)
|
||||
(package! company-lsp)
|
||||
|
||||
;; Rust
|
||||
(package! cargo)
|
||||
|
||||
;; Elixir
|
||||
(package! flycheck-credo)
|
||||
(package! flycheck-mix)
|
||||
(package! flycheck-dialyxir)
|
||||
|
||||
;; Lisp
|
||||
(package! paxedit)
|
||||
|
||||
;; Javascript
|
||||
(package! flow-minor-mode)
|
||||
(package! flycheck-flow)
|
||||
(package! company-flow)
|
||||
(package! prettier-js)
|
216
slack-snippets.el
Normal file
216
slack-snippets.el
Normal file
|
@ -0,0 +1,216 @@
|
|||
;;; private/grfn/slack-snippets.el -*- lexical-binding: t; -*-
|
||||
|
||||
(require 'dash)
|
||||
(require 'dash-functional)
|
||||
(require 'request)
|
||||
|
||||
;;;
|
||||
;;; Configuration
|
||||
;;;
|
||||
|
||||
(defvar slack/token nil
|
||||
"Legacy (https://api.slack.com/custom-integrations/legacy-tokens) access token")
|
||||
|
||||
(defvar slack/include-public-channels 't
|
||||
"Whether or not to inclue public channels in the list of conversations")
|
||||
|
||||
(defvar slack/include-private-channels 't
|
||||
"Whether or not to inclue public channels in the list of conversations")
|
||||
|
||||
(defvar slack/include-im 't
|
||||
"Whether or not to inclue IMs (private messages) in the list of conversations")
|
||||
|
||||
(defvar slack/include-mpim nil
|
||||
"Whether or not to inclue multi-person IMs (multi-person private messages) in
|
||||
the list of conversations")
|
||||
|
||||
;;;
|
||||
;;; Utilities
|
||||
;;;
|
||||
|
||||
(defmacro comment (&rest _body)
|
||||
"Comment out one or more s-expressions"
|
||||
nil)
|
||||
|
||||
(defun ->list (vec) (append vec nil))
|
||||
|
||||
(defun json-truthy? (x) (and x (not (equal :json-false x))))
|
||||
|
||||
;;;
|
||||
;;; Generic API integration
|
||||
;;;
|
||||
|
||||
(defvar slack/base-url "https://slack.com/api")
|
||||
|
||||
(defun slack/get (path params &optional callback)
|
||||
"params is an alist of query parameters"
|
||||
(let* ((params-callback (if (functionp params) `(() . ,params) (cons params callback)))
|
||||
(params (car params-callback)) (callback (cdr params-callback))
|
||||
(params (append `(("token" . ,slack/token)) params))
|
||||
(url (concat (file-name-as-directory slack/base-url) path)))
|
||||
(request url
|
||||
:type "GET"
|
||||
:params params
|
||||
:parser 'json-read
|
||||
:success (cl-function
|
||||
(lambda (&key data &allow-other-keys)
|
||||
(funcall callback data))))))
|
||||
|
||||
(defun slack/post (path params &optional callback)
|
||||
(let* ((params-callback (if (functionp params) `(() . ,params) (cons params callback)))
|
||||
(params (car params-callback)) (callback (cdr params-callback))
|
||||
(url (concat (file-name-as-directory slack/base-url) path)))
|
||||
(request url
|
||||
:type "POST"
|
||||
:data (json-encode params)
|
||||
:headers `(("Content-Type" . "application/json")
|
||||
("Authorization" . ,(format "Bearer %s" slack/token)))
|
||||
:success (cl-function
|
||||
(lambda (&key data &allow-other-keys)
|
||||
(funcall callback data))))))
|
||||
|
||||
|
||||
;;;
|
||||
;;; Specific API endpoints
|
||||
;;;
|
||||
|
||||
;; Users
|
||||
|
||||
(defun slack/users (cb)
|
||||
"Returns users as (id . name) pairs"
|
||||
(slack/get
|
||||
"users.list"
|
||||
(lambda (data)
|
||||
(->> data
|
||||
(assoc-default 'members)
|
||||
->list
|
||||
(-map (lambda (user)
|
||||
(cons (assoc-default 'id user)
|
||||
(assoc-default 'real_name user))))
|
||||
(-filter #'cdr)
|
||||
(funcall cb)))))
|
||||
|
||||
(comment
|
||||
(slack/get
|
||||
"users.list"
|
||||
(lambda (data) (setq response-data data)))
|
||||
|
||||
(slack/users (lambda (data) (setq --users data)))
|
||||
|
||||
)
|
||||
|
||||
;; Conversations
|
||||
|
||||
(defun slack/conversation-types ()
|
||||
(->>
|
||||
(list (when slack/include-public-channels "public_channel")
|
||||
(when slack/include-private-channels "private_channel")
|
||||
(when slack/include-im "im")
|
||||
(when slack/include-mpim "mpim"))
|
||||
(-filter #'identity)
|
||||
(s-join ",")))
|
||||
|
||||
(defun channel-label (chan users-alist)
|
||||
(cond
|
||||
((json-truthy? (assoc-default 'is_channel chan))
|
||||
(format "#%s" (assoc-default 'name chan)))
|
||||
((json-truthy? (assoc-default 'is_im chan))
|
||||
(let ((user-id (assoc-default 'user chan)))
|
||||
(format "Private message with %s" (assoc-default user-id users-alist))))
|
||||
((json-truthy? (assoc-default 'is_mpim chan))
|
||||
(->> chan
|
||||
(assoc-default 'purpose)
|
||||
(assoc-default 'value)))))
|
||||
|
||||
(defun slack/conversations (cb)
|
||||
"Calls `cb' with (id . '((label . \"label\") '(topic . \"topic\") '(purpose . \"purpose\"))) pairs"
|
||||
(slack/get
|
||||
"conversations.list"
|
||||
`(("types" . ,(slack/conversation-types))
|
||||
("exclude-archived" . "true"))
|
||||
(lambda (data)
|
||||
(setq --data data)
|
||||
(slack/users
|
||||
(lambda (users)
|
||||
(->> data
|
||||
(assoc-default 'channels)
|
||||
->list
|
||||
(-map
|
||||
(lambda (chan)
|
||||
(cons (assoc-default 'id chan)
|
||||
`((label . ,(channel-label chan users))
|
||||
(topic . ,(->> chan
|
||||
(assoc-default 'topic)
|
||||
(assoc-default 'value)))
|
||||
(purpose . ,(->> chan
|
||||
(assoc-default 'purpose)
|
||||
(assoc-default 'value)))))))
|
||||
(funcall cb)))))))
|
||||
|
||||
(comment
|
||||
(slack/get
|
||||
"conversations.list"
|
||||
'(("types" . "public_channel,private_channel,im,mpim"))
|
||||
(lambda (data) (setq response-data data)))
|
||||
|
||||
(slack/get
|
||||
"conversations.list"
|
||||
'(("types" . "im"))
|
||||
(lambda (data) (setq response-data data)))
|
||||
|
||||
(slack/conversations
|
||||
(lambda (convos) (setq --conversations convos)))
|
||||
|
||||
)
|
||||
|
||||
;; Messages
|
||||
|
||||
(cl-defun slack/post-message
|
||||
(&key text channel-id (on-success #'identity))
|
||||
(slack/post "chat.postMessage"
|
||||
`((text . ,text)
|
||||
(channel . ,channel-id)
|
||||
(as_user . t))
|
||||
on-success))
|
||||
|
||||
(comment
|
||||
|
||||
(slack/post-message
|
||||
:text "hi slackbot"
|
||||
:channel-id slackbot-channel-id
|
||||
:on-success (lambda (data) (setq resp data)))
|
||||
|
||||
)
|
||||
|
||||
;;;
|
||||
;;; Posting code snippets to slack
|
||||
;;;
|
||||
|
||||
(defun prompt-for-channel (cb)
|
||||
(slack/conversations
|
||||
(lambda (conversations)
|
||||
(ivy-read
|
||||
"Select channel: "
|
||||
;; TODO want to potentially use purpose / topic stuff here
|
||||
(-map (lambda (chan) (let ((label (assoc-default 'label (cdr chan)))
|
||||
(id (car chan)))
|
||||
(propertize label 'channel-id id)))
|
||||
conversations)
|
||||
:history 'slack/channel-history
|
||||
:action (lambda (selected)
|
||||
(let ((channel-id (get-text-property 0 'channel-id selected)))
|
||||
(funcall cb channel-id)
|
||||
(message "Sent message to %s" selected))))))
|
||||
nil)
|
||||
|
||||
(defun slack-send-code-snippet (&optional snippet-text)
|
||||
(interactive)
|
||||
(when-let ((snippet-text (or snippet-text
|
||||
(buffer-substring-no-properties (mark) (point)))))
|
||||
(prompt-for-channel
|
||||
(lambda (channel-id)
|
||||
(slack/post-message
|
||||
:text (format "```\n%s```" snippet-text)
|
||||
:channel-id channel-id)))))
|
||||
|
||||
(provide 'slack-snippets)
|
26
snippets/haskell-mode/benchmark-module
Normal file
26
snippets/haskell-mode/benchmark-module
Normal file
|
@ -0,0 +1,26 @@
|
|||
# key: bench
|
||||
# name: benchmark-module
|
||||
# expand-env: ((yas-indent-line (quote fixed)))
|
||||
# --
|
||||
--------------------------------------------------------------------------------
|
||||
module ${1:`(if (not buffer-file-name) "Module"
|
||||
(let ((name (file-name-sans-extension (buffer-file-name)))
|
||||
(case-fold-search nil))
|
||||
(if (cl-search "bench/" name)
|
||||
(replace-regexp-in-string "/" "."
|
||||
(replace-regexp-in-string "^\/[^A-Z]*" ""
|
||||
(car (last (split-string name "src")))))
|
||||
(file-name-nondirectory name))))`} ( benchmark, main ) where
|
||||
--------------------------------------------------------------------------------
|
||||
import Bench.Prelude
|
||||
--------------------------------------------------------------------------------
|
||||
import ${1:$(s-chop-suffix "Bench" yas-text)}
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
main :: IO ()
|
||||
main = defaultMain [benchmark]
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
benchmark :: Benchmark
|
||||
benchmark = bgroup "${1:$(->> yas-text (s-chop-suffix "Bench") (s-split ".") -last-item)}" [bench "something dumb" $ nf (1 +) (1 :: Int)]
|
6
snippets/haskell-mode/header
Normal file
6
snippets/haskell-mode/header
Normal file
|
@ -0,0 +1,6 @@
|
|||
# key: hh
|
||||
# name: header
|
||||
# expand-env: ((yas-indent-line 'fixed))
|
||||
# --
|
||||
----------------------------------------------------------------------
|
||||
$2
|
8
snippets/haskell-mode/hedgehog-generator
Normal file
8
snippets/haskell-mode/hedgehog-generator
Normal file
|
@ -0,0 +1,8 @@
|
|||
# key: gen
|
||||
# name: Hedgehog Generator
|
||||
# expand-env: ((yas-indent-line (quote fixed)))
|
||||
# --
|
||||
gen${1:Foo} :: Gen $1
|
||||
gen$1 = do
|
||||
$2
|
||||
pure $1{..}
|
9
snippets/haskell-mode/hedgehog-property
Normal file
9
snippets/haskell-mode/hedgehog-property
Normal file
|
@ -0,0 +1,9 @@
|
|||
# -*- mode: snippet -*-
|
||||
# name: Hedgehog Property
|
||||
# key: hprop
|
||||
# expand-env: ((yas-indent-line 'fixed))
|
||||
# --
|
||||
hprop_${1:somethingIsAlwaysTrue} :: Property
|
||||
hprop_$1 = property $ do
|
||||
${2:x} <- forAll ${3:Gen.int $ Range.linear 1 100}
|
||||
${4:x === x}
|
7
snippets/haskell-mode/lens.field
Normal file
7
snippets/haskell-mode/lens.field
Normal file
|
@ -0,0 +1,7 @@
|
|||
# -*- mode: snippet -*-
|
||||
# name: lens.field
|
||||
# key: lens
|
||||
# expand-env: ((yas-indent-line 'fixed))
|
||||
# --
|
||||
${1:field} :: Lens' ${2:Source} ${3:Target}
|
||||
$1 = lens _${4:sourceField} $ \\${2:$(-> yas-text s-word-initials s-downcase)} ${4:$(-> yas-text s-word-initials s-downcase)} -> ${2:$(-> yas-text s-word-initials s-downcase)} { _$4 = ${4:$(-> yas-text s-word-initials s-downcase)} }
|
32
snippets/haskell-mode/module
Normal file
32
snippets/haskell-mode/module
Normal file
|
@ -0,0 +1,32 @@
|
|||
# -*- mode: snippet -*-
|
||||
# key: module
|
||||
# name: module
|
||||
# condition: (= (length "module") (current-column))
|
||||
# expand-env: ((yas-indent-line 'fixed))
|
||||
# contributor: Luke Hoersten <luke@hoersten.org>
|
||||
# --
|
||||
----------------------------------------------------------------------
|
||||
-- |
|
||||
-- Module : $1
|
||||
-- Description : $2
|
||||
-- Maintainer : Griffin Smith <grfn@urbint.com>
|
||||
-- Maturity : ${3:Draft, Usable, Maintained, OR MatureAF}
|
||||
--
|
||||
-- $4
|
||||
----------------------------------------------------------------------
|
||||
module ${1:`(if (not buffer-file-name) "Module"
|
||||
(let ((name (file-name-sans-extension (buffer-file-name)))
|
||||
(case-fold-search nil))
|
||||
(if (or (cl-search "src/" name)
|
||||
(cl-search "test/" name))
|
||||
(replace-regexp-in-string "/" "."
|
||||
(replace-regexp-in-string "^\/[^A-Z]*" ""
|
||||
(car (last (split-string name "src")))))
|
||||
(file-name-nondirectory name))))`}
|
||||
(
|
||||
) where
|
||||
----------------------------------------------------------------------
|
||||
import Prelude
|
||||
----------------------------------------------------------------------
|
||||
|
||||
$0
|
21
snippets/haskell-mode/test-module
Normal file
21
snippets/haskell-mode/test-module
Normal file
|
@ -0,0 +1,21 @@
|
|||
# -*- mode: snippet -*-
|
||||
# name: test-module
|
||||
# key: test
|
||||
# --
|
||||
{-# LANGUAGE ApplicativeDo #-}
|
||||
--------------------------------------------------------------------------------
|
||||
module ${1:`(if (not buffer-file-name) "Module"
|
||||
(let ((name (file-name-sans-extension (buffer-file-name)))
|
||||
(case-fold-search nil))
|
||||
(if (cl-search "test/" name)
|
||||
(replace-regexp-in-string "/" "."
|
||||
(replace-regexp-in-string "^\/[^A-Z]*" ""
|
||||
(car (last (split-string name "src")))))
|
||||
(file-name-nondirectory name))))`} where
|
||||
--------------------------------------------------------------------------------
|
||||
import Test.Prelude
|
||||
import qualified Hedgehog.Gen as Gen
|
||||
import qualified Hedgehog.Range as Range
|
||||
--------------------------------------------------------------------------------
|
||||
import ${1:$(s-chop-suffix "Test" yas-text)}
|
||||
--------------------------------------------------------------------------------
|
6
snippets/haskell-mode/undefined
Normal file
6
snippets/haskell-mode/undefined
Normal file
|
@ -0,0 +1,6 @@
|
|||
# -*- mode: snippet -*-
|
||||
# name: undefined
|
||||
# key: u
|
||||
# expand-env: ((yas-indent-line 'fixed) (yas-wrap-around-region 'nil))
|
||||
# --
|
||||
undefined$1
|
5
snippets/org-mode/date
Normal file
5
snippets/org-mode/date
Normal file
|
@ -0,0 +1,5 @@
|
|||
# -*- mode: snippet -*-
|
||||
# key: date
|
||||
# name: date.org
|
||||
# --
|
||||
[`(format-time-string "%Y-%m-%d")`]$0
|
5
snippets/org-mode/date-time
Normal file
5
snippets/org-mode/date-time
Normal file
|
@ -0,0 +1,5 @@
|
|||
# -*- mode: snippet -*-
|
||||
# name: date-time
|
||||
# key: dt
|
||||
# --
|
||||
[`(format-time-string "%Y-%m-%d %H:%m:%S")`]
|
5
snippets/org-mode/nologdone
Normal file
5
snippets/org-mode/nologdone
Normal file
|
@ -0,0 +1,5 @@
|
|||
# -*- mode: snippet -*-
|
||||
# name: nologdone
|
||||
# key: nologdone
|
||||
# --
|
||||
#+STARTUP: nologdone$0
|
8
snippets/org-mode/source-block
Normal file
8
snippets/org-mode/source-block
Normal file
|
@ -0,0 +1,8 @@
|
|||
# -*- mode: snippet -*-
|
||||
# name: source-block
|
||||
# key: src
|
||||
# expand-env: ((yas-indent-line 'fixed))
|
||||
# --
|
||||
#+BEGIN_SRC ${1:elisp}
|
||||
$2
|
||||
#+END_SRC
|
5
snippets/snippet-mode/indent
Normal file
5
snippets/snippet-mode/indent
Normal file
|
@ -0,0 +1,5 @@
|
|||
# -*- mode: snippet -*-
|
||||
# name: indent
|
||||
# key: indent
|
||||
# --
|
||||
# expand-env: ((yas-indent-line 'fixed))
|
5
snippets/text-mode/date
Normal file
5
snippets/text-mode/date
Normal file
|
@ -0,0 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# name: date
|
||||
# key: date
|
||||
# --
|
||||
`(format-time-string "%Y-%m-%d")`$0
|
192
splitjoin.el
Normal file
192
splitjoin.el
Normal file
|
@ -0,0 +1,192 @@
|
|||
;;; private/grfn/splitjoin.el -*- lexical-binding: t; -*-
|
||||
|
||||
(require 'dash)
|
||||
(load! utils)
|
||||
|
||||
;;;
|
||||
;;; Vars
|
||||
;;;
|
||||
|
||||
(defvar +splitjoin/split-callbacks '()
|
||||
"Alist mapping major mode symbol names to lists of split callbacks")
|
||||
|
||||
(defvar +splitjoin/join-callbacks '()
|
||||
"Alist mapping major mode symbol names to lists of join callbacks")
|
||||
|
||||
|
||||
|
||||
;;;
|
||||
;;; Definition macros
|
||||
;;;
|
||||
|
||||
(defmacro +splitjoin/defsplit (mode name &rest body)
|
||||
`(setf
|
||||
(alist-get ',name (alist-get ,mode +splitjoin/split-callbacks))
|
||||
(λ! () ,@body)))
|
||||
|
||||
(defmacro +splitjoin/defjoin (mode name &rest body)
|
||||
`(setf
|
||||
(alist-get ',name (alist-get ,mode +splitjoin/join-callbacks))
|
||||
(λ! () ,@body)))
|
||||
|
||||
;;;
|
||||
;;; Commands
|
||||
;;;
|
||||
|
||||
(defun +splitjoin/split ()
|
||||
(interactive)
|
||||
(when-let (callbacks (->> +splitjoin/split-callbacks
|
||||
(alist-get major-mode)
|
||||
(-map #'cdr)))
|
||||
(find-if #'funcall callbacks)))
|
||||
|
||||
(defun +splitjoin/join ()
|
||||
(interactive)
|
||||
(when-let (callbacks (->> +splitjoin/join-callbacks
|
||||
(alist-get major-mode)
|
||||
(-map #'cdr)))
|
||||
(find-if #'funcall callbacks)))
|
||||
|
||||
|
||||
;;;
|
||||
;;; Splits and joins
|
||||
;;; TODO: this should probably go in a file-per-language
|
||||
;;;
|
||||
|
||||
(+splitjoin/defjoin
|
||||
'elixir-mode
|
||||
join-do
|
||||
(let* ((function-pattern (rx (and (zero-or-more whitespace)
|
||||
"do"
|
||||
(zero-or-more whitespace)
|
||||
(optional (and "#" (zero-or-more anything)))
|
||||
eol)))
|
||||
(end-pattern (rx bol
|
||||
(zero-or-more whitespace)
|
||||
"end"
|
||||
(zero-or-more whitespace)
|
||||
eol))
|
||||
(else-pattern (rx bol
|
||||
(zero-or-more whitespace)
|
||||
"else"
|
||||
(zero-or-more whitespace)
|
||||
eol))
|
||||
(lineno (line-number-at-pos))
|
||||
(line (thing-at-point 'line t)))
|
||||
(when-let ((do-start-pos (string-match function-pattern line)))
|
||||
(cond
|
||||
((string-match-p end-pattern (get-line (inc lineno)))
|
||||
(modify-then-indent
|
||||
(goto-line-char do-start-pos)
|
||||
(insert ",")
|
||||
(goto-char (line-end-position))
|
||||
(insert ": nil")
|
||||
(line-move 1)
|
||||
(delete-line))
|
||||
t)
|
||||
|
||||
((string-match-p end-pattern (get-line (+ 2 lineno)))
|
||||
(modify-then-indent
|
||||
(goto-line-char do-start-pos)
|
||||
(insert ",")
|
||||
(goto-char (line-end-position))
|
||||
(insert ":")
|
||||
(join-line t)
|
||||
(line-move 1)
|
||||
(delete-line))
|
||||
t)
|
||||
|
||||
((and (string-match-p else-pattern (get-line (+ 2 lineno)))
|
||||
(string-match-p end-pattern (get-line (+ 4 lineno))))
|
||||
(modify-then-indent
|
||||
(goto-line-char do-start-pos)
|
||||
(insert ",")
|
||||
(goto-char (line-end-position))
|
||||
(insert ":")
|
||||
(join-line t)
|
||||
(goto-eol)
|
||||
(insert ",")
|
||||
(join-line t)
|
||||
(goto-eol)
|
||||
(insert ":")
|
||||
(join-line t)
|
||||
(line-move 1)
|
||||
(delete-line))
|
||||
t)))))
|
||||
|
||||
(comment
|
||||
(string-match (rx (and bol
|
||||
"if "
|
||||
(one-or-more anything)
|
||||
","
|
||||
(zero-or-more whitespace)
|
||||
"do:"
|
||||
(one-or-more anything)
|
||||
","
|
||||
(zero-or-more whitespace)
|
||||
"else:"
|
||||
(one-or-more anything)))
|
||||
"if 1, do: nil, else: nil")
|
||||
|
||||
)
|
||||
|
||||
(+splitjoin/defsplit
|
||||
'elixir-mode
|
||||
split-do-with-optional-else
|
||||
(let* ((if-with-else-pattern (rx (and bol
|
||||
(one-or-more anything)
|
||||
","
|
||||
(zero-or-more whitespace)
|
||||
"do:"
|
||||
(one-or-more anything)
|
||||
(optional
|
||||
","
|
||||
(zero-or-more whitespace)
|
||||
"else:"
|
||||
(one-or-more anything)))))
|
||||
(current-line (get-line)))
|
||||
(when (string-match if-with-else-pattern current-line)
|
||||
(modify-then-indent
|
||||
(assert (goto-regex-on-line ",[[:space:]]*do:"))
|
||||
(delete-char 1)
|
||||
(assert (goto-regex-on-line ":"))
|
||||
(delete-char 1)
|
||||
(insert "\n")
|
||||
(when (goto-regex-on-line-r ",[[:space:]]*else:")
|
||||
(delete-char 1)
|
||||
(insert "\n")
|
||||
(assert (goto-regex-on-line ":"))
|
||||
(delete-char 1)
|
||||
(insert "\n"))
|
||||
(goto-eol)
|
||||
(insert "\nend"))
|
||||
t)))
|
||||
|
||||
(comment
|
||||
(+splitjoin/defsplit 'elixir-mode split-def
|
||||
(let ((function-pattern (rx (and ","
|
||||
(zero-or-more whitespace)
|
||||
"do:")))
|
||||
(line (thing-at-point 'line t)))
|
||||
(when-let (idx (string-match function-pattern line))
|
||||
(let ((beg (line-beginning-position))
|
||||
(orig-line-char (- (point) (line-beginning-position))))
|
||||
(save-mark-and-excursion
|
||||
(goto-line-char idx)
|
||||
(delete-char 1)
|
||||
(goto-line-char (string-match ":" (thing-at-point 'line t)))
|
||||
(delete-char 1)
|
||||
(insert "\n")
|
||||
(goto-eol)
|
||||
(insert "\n")
|
||||
(insert "end")
|
||||
(evil-indent beg (+ (line-end-position) 1))))
|
||||
(goto-line-char orig-line-char)
|
||||
t))))
|
||||
|
||||
(+splitjoin/defjoin
|
||||
'elixir-mode
|
||||
join-if-with-else
|
||||
(let* ((current-line (thing-at-point 'line)))))
|
||||
|
||||
(provide 'splitjoin)
|
68
tests/splitjoin_test.el
Normal file
68
tests/splitjoin_test.el
Normal file
|
@ -0,0 +1,68 @@
|
|||
;;; private/grfn/tests/splitjoin_test.el -*- lexical-binding: t; -*-
|
||||
|
||||
(require 'ert)
|
||||
;; (load! 'splitjoin)
|
||||
;; (load! 'utils)
|
||||
; (require 'splitjoin)
|
||||
|
||||
;;; Helpers
|
||||
|
||||
(defvar *test-buffer* nil)
|
||||
(make-variable-buffer-local '*test-buffer*)
|
||||
|
||||
(defun test-buffer ()
|
||||
(when (not *test-buffer*)
|
||||
(setq *test-buffer* (get-buffer-create "test-buffer")))
|
||||
*test-buffer*)
|
||||
|
||||
(defmacro with-test-buffer (&rest body)
|
||||
`(with-current-buffer (test-buffer)
|
||||
,@body))
|
||||
|
||||
(defun set-test-buffer-mode (mode)
|
||||
(let ((mode (if (functionp mode) mode
|
||||
(-> mode symbol-name (concat "-mode") intern))))
|
||||
(assert (functionp mode))
|
||||
(with-test-buffer (funcall mode))))
|
||||
|
||||
(defmacro set-test-buffer-contents (contents)
|
||||
(with-test-buffer
|
||||
(erase-buffer)
|
||||
(insert contents)))
|
||||
|
||||
(defun test-buffer-contents ()
|
||||
(with-test-buffer (substring-no-properties (buffer-string))))
|
||||
|
||||
(defmacro assert-test-buffer-contents (expected-contents)
|
||||
`(should (equal (string-trim (test-buffer-contents))
|
||||
(string-trim ,expected-contents))))
|
||||
|
||||
(defmacro should-join-to (mode original-contents expected-contents)
|
||||
`(progn
|
||||
(set-test-buffer-mode ,mode)
|
||||
(set-test-buffer-contents ,original-contents)
|
||||
(with-test-buffer (+splitjoin/join))
|
||||
(assert-test-buffer-contents ,expected-contents)))
|
||||
|
||||
(defmacro should-split-to (mode original-contents expected-contents)
|
||||
`(progn
|
||||
(set-test-buffer-mode ,mode)
|
||||
(set-test-buffer-contents ,original-contents)
|
||||
(with-test-buffer (+splitjoin/split))
|
||||
(assert-test-buffer-contents ,expected-contents)))
|
||||
|
||||
(defmacro should-splitjoin (mode joined-contents split-contents)
|
||||
`(progn
|
||||
(should-split-to ,mode ,joined-contents ,split-contents)
|
||||
(should-join-to ,mode ,split-contents ,joined-contents)))
|
||||
|
||||
;;; Tests
|
||||
|
||||
;; Elixir
|
||||
(ert-deftest elixir-if-splitjoin-test ()
|
||||
(should-splitjoin 'elixir
|
||||
"if predicate?(), do: result"
|
||||
"if predicate?() do
|
||||
result
|
||||
end"))
|
||||
|
85
themes/grfn-solarized-light-theme.el
Normal file
85
themes/grfn-solarized-light-theme.el
Normal file
|
@ -0,0 +1,85 @@
|
|||
(require 'solarized)
|
||||
|
||||
;; (defun grfn-solarized-theme ()
|
||||
;; (custom-theme-set-faces
|
||||
;; theme-name
|
||||
;; `(font-lock-doc-face ((,class (:foreground ,s-base1))))
|
||||
;; `(font-lock-preprocessor-face ((,class (:foreground ,red))))
|
||||
;; `(font-lock-keyword-face ((,class (:foreground ,green))))
|
||||
|
||||
;; `(elixir-attribute-face ((,class (:foreground ,blue))))
|
||||
;; `(elixir-atom-face ((,class (:foreground ,cyan))))))
|
||||
|
||||
(setq +solarized-s-base03 "#002b36"
|
||||
+solarized-s-base02 "#073642"
|
||||
;; emphasized content
|
||||
+solarized-s-base01 "#586e75"
|
||||
;; primary content
|
||||
+solarized-s-base00 "#657b83"
|
||||
+solarized-s-base0 "#839496"
|
||||
;; comments
|
||||
+solarized-s-base1 "#93a1a1"
|
||||
;; background highlight light
|
||||
+solarized-s-base2 "#eee8d5"
|
||||
;; background light
|
||||
+solarized-s-base3 "#fdf6e3"
|
||||
|
||||
;; Solarized accented colors
|
||||
+solarized-yellow "#b58900"
|
||||
+solarized-orange "#cb4b16"
|
||||
+solarized-red "#dc322f"
|
||||
+solarized-magenta "#d33682"
|
||||
+solarized-violet "#6c71c4"
|
||||
+solarized-blue "#268bd2"
|
||||
+solarized-cyan "#2aa198"
|
||||
+solarized-green "#859900"
|
||||
|
||||
;; Darker and lighter accented colors
|
||||
;; Only use these in exceptional circumstances!
|
||||
+solarized-yellow-d "#7B6000"
|
||||
+solarized-yellow-l "#DEB542"
|
||||
+solarized-orange-d "#8B2C02"
|
||||
+solarized-orange-l "#F2804F"
|
||||
+solarized-red-d "#990A1B"
|
||||
+solarized-red-l "#FF6E64"
|
||||
+solarized-magenta-d "#93115C"
|
||||
+solarized-magenta-l "#F771AC"
|
||||
+solarized-violet-d "#3F4D91"
|
||||
+solarized-violet-l "#9EA0E5"
|
||||
+solarized-blue-d "#00629D"
|
||||
+solarized-blue-l "#69B7F0"
|
||||
+solarized-cyan-d "#00736F"
|
||||
+solarized-cyan-l "#69CABF"
|
||||
+solarized-green-d "#546E00"
|
||||
+solarized-green-l "#B4C342")
|
||||
|
||||
|
||||
(deftheme grfn-solarized-light "The light variant of Griffin's solarized theme")
|
||||
|
||||
(create-solarized-theme
|
||||
'light 'grfn-solarized-light
|
||||
(lambda ()
|
||||
(custom-theme-set-faces
|
||||
'grfn-solarized-light
|
||||
`(font-lock-doc-face ((t (:foreground ,+solarized-s-base1))))
|
||||
`(font-lock-preprocessor-face ((t (:foreground ,+solarized-red))))
|
||||
`(font-lock-keyword-face ((t (:foreground ,+solarized-green))))
|
||||
|
||||
`(elixir-attribute-face ((t (:foreground ,+solarized-blue))))
|
||||
`(elixir-atom-face ((t (:foreground ,+solarized-cyan))))
|
||||
)
|
||||
|
||||
))
|
||||
|
||||
(custom-theme-set-faces
|
||||
'grfn-solarized-light
|
||||
`(font-lock-doc-face ((t (:foreground ,+solarized-s-base1))))
|
||||
`(font-lock-preprocessor-face ((t (:foreground ,+solarized-red))))
|
||||
`(font-lock-keyword-face ((t (:foreground ,+solarized-green))))
|
||||
|
||||
`(elixir-attribute-face ((t (:foreground ,+solarized-blue))))
|
||||
`(elixir-atom-face ((t (:foreground ,+solarized-cyan))))
|
||||
)
|
||||
|
||||
(provide-theme 'grfn-solarized-light)
|
||||
|
92
utils.el
Normal file
92
utils.el
Normal file
|
@ -0,0 +1,92 @@
|
|||
;;; private/grfn/utils.el -*- lexical-binding: t; -*-
|
||||
|
||||
|
||||
;; Elisp Extras
|
||||
|
||||
(defmacro comment (&rest _body)
|
||||
"Comment out one or more s-expressions"
|
||||
nil)
|
||||
|
||||
(defun inc (x) "Returns x + 1" (+ 1 x))
|
||||
(defun dec (x) "Returns x - 1" (- x 1))
|
||||
|
||||
|
||||
;;
|
||||
;; Text editing utils
|
||||
;;
|
||||
|
||||
;; Reading strings
|
||||
|
||||
(defun get-char (&optional point)
|
||||
"Get the character at the given `point' (defaulting to the current point),
|
||||
without properties"
|
||||
(let ((point (or point (point))))
|
||||
(buffer-substring-no-properties point (+ 1 point))))
|
||||
|
||||
(defun get-line (&optional lineno)
|
||||
"Read the line number `lineno', or the current line if `lineno' is nil, and
|
||||
return it as a string stripped of all text properties"
|
||||
(let ((current-line (line-number-at-pos)))
|
||||
(if (or (not lineno)
|
||||
(= current-line lineno))
|
||||
(thing-at-point 'line t)
|
||||
(save-mark-and-excursion
|
||||
(line-move (- lineno (line-number-at-pos)))
|
||||
(thing-at-point 'line t)))))
|
||||
|
||||
(defun get-line-point ()
|
||||
"Get the position in the current line of the point"
|
||||
(- (point) (line-beginning-position)))
|
||||
|
||||
;; Moving in the file
|
||||
|
||||
(defun goto-line-char (pt)
|
||||
"Moves the point to the given position expressed as an offset from the start
|
||||
of the line"
|
||||
(goto-char (+ (line-beginning-position) pt)))
|
||||
|
||||
(defun goto-eol ()
|
||||
"Moves to the end of the current line"
|
||||
(goto-char (line-end-position)))
|
||||
|
||||
(defun goto-regex-on-line (regex)
|
||||
"Moves the point to the first occurrence of `regex' on the current line.
|
||||
Returns nil if the regex did not match, non-nil otherwise"
|
||||
(when-let ((current-line (get-line))
|
||||
(line-char (string-match regex current-line)))
|
||||
(goto-line-char line-char)))
|
||||
|
||||
(defun goto-regex-on-line-r (regex)
|
||||
"Moves the point to the *last* occurrence of `regex' on the current line.
|
||||
Returns nil if the regex did not match, non-nil otherwise"
|
||||
(when-let ((current-line (get-line))
|
||||
(modified-regex (concat ".*\\(" regex "\\)"))
|
||||
(_ (string-match modified-regex current-line))
|
||||
(match-start (match-beginning 1)))
|
||||
(goto-line-char match-start)))
|
||||
|
||||
(comment
|
||||
(progn
|
||||
(string-match (rx (and (zero-or-more anything)
|
||||
(group "foo" "foo")))
|
||||
"foofoofoo")
|
||||
(match-beginning 1)))
|
||||
|
||||
;; Changing file contents
|
||||
|
||||
(defun delete-line ()
|
||||
"Remove the line at the current point"
|
||||
(delete-region (line-beginning-position)
|
||||
(inc (line-end-position))))
|
||||
|
||||
(defmacro modify-then-indent (&rest body)
|
||||
"Modify text in the buffer according to body, then re-indent from where the
|
||||
cursor started to where the cursor ended up, then return the cursor to where
|
||||
it started."
|
||||
`(let ((beg (line-beginning-position))
|
||||
(orig-line-char (- (point) (line-beginning-position))))
|
||||
(atomic-change-group
|
||||
(save-mark-and-excursion
|
||||
,@body
|
||||
(evil-indent beg (+ (line-end-position) 1))))
|
||||
(goto-line-char orig-line-char)))
|
Loading…
Reference in a new issue