mirror of
https://github.com/doomemacs/doomemacs
synced 2025-08-03 12:27:26 -05:00
Merge branch 'develop'
* develop: (173 commits) v2.0.6 bump Add zunit file template & file extension Remove +workspace/cleanup (doom/cleanup-buffers is better) Remove org/org dependency on doom-themes General refactor & docstring updates Revert "Preload modules before compiling #219" Fix 'variable reference to nil’ compiler warning Fix markdown specific keybindings being added to global map Fix bad doom/other-popup alias breaking which-key #223 Preload modules before compiling #219 Popup library: minor refactor & appease byte-compiler Fix compile error caused by defunct keybinding #219 Remove org/org-notebook Add org unit tests to init.test.el Add unit test file template Fix modeline duplication in buffer-file-name :help-echo org/org: new command +org/remove-link, bound to C-c C-S-l org/org: add tests for +org/insert-item Add test helper macros to test.el lib +org/insert-item: fix one-too-many prepended newlines in 1st-level headers ...
This commit is contained in:
@ -10,6 +10,7 @@ before_install:
|
||||
env:
|
||||
- EVM_EMACS=emacs-25.1-travis
|
||||
- EVM_EMACS=emacs-25.2-travis
|
||||
- EVM_EMACS=emacs-25.3-travis
|
||||
script:
|
||||
- emacs --version
|
||||
- make test
|
||||
|
178
CHANGELOG.org
178
CHANGELOG.org
@ -1,7 +1,7 @@
|
||||
#+TITLE: Changelog
|
||||
|
||||
- [[#todo][Todo]]
|
||||
- [[#unreleased-master][Unreleased (master)]]
|
||||
- [[#unreleased-develop][Unreleased (develop)]]
|
||||
- [[#206-oct-05-2017][2.0.6 (Oct 05, 2017)]]
|
||||
- [[#205-sep-03-2017][2.0.5 (Sep 03, 2017)]]
|
||||
- [[#204-jul-14-2017][2.0.4 (Jul 14, 2017)]]
|
||||
- [[#203-jun-11-2017][2.0.3 (Jun 11, 2017)]]
|
||||
@ -9,72 +9,116 @@
|
||||
- [[#201-apr-8-2017][2.0.1 (Apr 8, 2017)]]
|
||||
- [[#200-jan-17-2017][2.0.0 (Jan 17, 2017)]]
|
||||
|
||||
* Todo
|
||||
+ *Potential plugins:*
|
||||
+ =app/present= [[https://github.com/larstvei/Focus][focus]], for presenting code
|
||||
+ [[https://github.com/emacs-lsp/lsp-mode][lsp-mode]], client for MS Language Server Protocol, keep an eye on this
|
||||
+ =lang/javascript= [[https://github.com/NicolasPetton/Indium][indium]] (IDE), keep an eye on this
|
||||
+ =lang/javascript= [[https://github.com/codesuki/add-node-modules-path][add-node-modules-path]] (adds node_modules to ~exec-path~)
|
||||
+ =lang/javascript= [[https://github.com/lbolla/emacs-flycheck-flow][flycheck-flow]] (Flow support for JS)
|
||||
+ =lang/org= [[https://github.com/Malabarba/latex-extra][orgit]] (org links to magit buffers)
|
||||
+ =lang/org= [[https://github.com/jkitchin/org-ref][org-ref]] (bibtex/citation helper)
|
||||
+ =lang/org= [[https://github.com/tashrifsanil/org-easy-img-insert][org-easy-img-insert]]
|
||||
+ =lang/latex= [[https://github.com/Malabarba/latex-extra][latex-extra]] (utility commands)
|
||||
+ =lang/latex= [[**https://github.com/jsinglet/latex-preview-pane][latex-preview-pane]]
|
||||
+ =lang/julia= [[ https://github.com/dennisog/julia-shell-mode][julia-shell]] (unsure if better than inferior-julia in julia-mode)
|
||||
+ =lang/python= [[https://github.com/Wilfred/pyimport][pyimport]] or [[https://github.com/anachronic/importmagic.el][importmagic]]
|
||||
+ [[https://github.com/mhayashi1120/Emacs-imagex][emacs-imagex]], for manipulating images at point (zooming?)
|
||||
+ =tools/term= [[https://github.com/riscy/shx-for-emacs][shx]], an extension for the shell in Emacs
|
||||
+ =app/crm= [[https://github.com/skeeto/emacsql][emacsql]], a sqlite backend; possibly useful for CRM storage.
|
||||
+ =core= [[https://github.com/Wilfred/helpful][helpful]], a better help buffer; replacement for ~describe-function~?
|
||||
+ *Planned modules:*
|
||||
+ =app/crm= -- Customer Relations Management, in Emacs, using org-mode.
|
||||
+ =app/write= -- Make Emacs into a focused plaintext word processor (using markdown, org and rst) for writing papers and stories.
|
||||
+ =app/regex= -- PCRE IDE, with live buffer matching, search/replace support, and an export-to-code feature for various languages.
|
||||
+ +Perl backend+
|
||||
+ Search and replace support
|
||||
+ Highlight replaced segments
|
||||
+ Export-to-code feature for:
|
||||
+ python (use ~re~ or ~regex~)
|
||||
+ php (~preg_(match(_all)?|replace)~)
|
||||
+ ruby (~%r[.+]~)
|
||||
+ javascript (node) (~/.+/.test(...)~)
|
||||
+ C (~regex.h~ + ~regcomp~)
|
||||
+ C++ (~regex reg(regexp, ...)~)
|
||||
+ Syntax highlighter for ~+regex-mode~ (plus make it a major mode)
|
||||
+ Optimize: communicate with perl process (with ~make-process~ instead of ~call-process~)
|
||||
+ =org/org-publish= -- publishing org files to HTML (thanks to [[https://github.com/matthewgraybosch][matthewgraybosch]])
|
||||
+ =org/org-attach= -- my own, simpler attachment system with drag-drop image attachment support and centralized storage.
|
||||
+ =app/torrents= -- Emacs as a torrent client (powered by transmission.el)
|
||||
+ =core-ui= Replace or fix ~winner-mode~ unreliability (will close windows trying to revive killed buffers). Perhaps make ~doom/kill-this-buffer~ only disassociate buffer from persp-mode or bury buffer if persp-mode is inactive.
|
||||
+ =org=
|
||||
+ Better shackle + org-agenda integration
|
||||
+ Fix janky visual line motions (~evil-next-visual-line~, etc)
|
||||
+ Fix janky cursor positioning when jumping between org-table cells from insert mode.
|
||||
+ Certain characters/keys--when typed in a table--cause the cell to shrink (likely cause: custom self-insert-char behavior -- like smartparens pairs & custom SPC/BKSPC binds)
|
||||
+ =feature/jump= Automatic etags generation (for dwim go-to-definition and, perhaps, code-completion for some languages; lua maybe?).
|
||||
+ =lang/php= Automatic and async tags generation using [[https://github.com/xcwen/phpctags][phpctags]].
|
||||
+ =lang/lua= True, dynamic code-completion? Looks like [[https://github.com/immerrr/lua-mode/pull/119][this PR in lua-mode]] may have the answer. Does it make ~company-lua~ redundant?
|
||||
+ =tools/upload= Add ~+upload/open-remote-file~ command to open current file on the remote (with TRAMP).
|
||||
+ Add =bin/org-alert= script -- a cron script that scans TODOs in org files and dispatches system alerts.
|
||||
+ =feature/workspaces= Add a bookmarks feature, but for wconfs, that can revive file buffers. Also needs an interface.
|
||||
+ =ui/doom-modeline=
|
||||
+ Fix hardcoded spacing in between segments.
|
||||
+ Fix ~0/0~ leftover panel in modeline (caused by lingering anzu state).
|
||||
+ Update =bin/org-capture= to read from stdin in the absence of arguments.
|
||||
+ =core-popups= Add support for moving popup windows to the ~+evil/window-move-*~ commands #171
|
||||
* Unreleased (develop)
|
||||
|
||||
* Unreleased (master)
|
||||
+ =doom=
|
||||
+ Added new module: ~lang/ledger~, for editing ledger files.
|
||||
+ Fixed ~make update~ to work even if Doom is installed somewhere other than ~\~/.emacs.d~ (see [[https://github.com/hlissner/doom-emacs/issues/190][#190]]).
|
||||
* 2.0.6 (Oct 05, 2017)
|
||||
+ *Module changes:*
|
||||
+ Add =lang/ledger=
|
||||
+ Add =ui/vi-tilde-fringe= -- used to be in =core-ui=; indicates beyond-EOB,
|
||||
using tildes in the fringe (inspired by vim).
|
||||
+ Add =feature/services= -- used to be =tools/prodigy=. Adds a way of managing
|
||||
external processes and services.
|
||||
+ Add =tools/make= -- for running project Makefile commands from Emacs.
|
||||
+ Add =tools/imenu= -- adds a sidebar for imenu (~imenu-list~), and a way of
|
||||
jumping to imenu entries across all open buffers (~imenu-anywhere~).
|
||||
+ Move =feature/hydra= into =core-keybinds=.
|
||||
+ Rename =feature/debug= to =feature/debugger= (and disabled it by default; it
|
||||
is currently unstable and needs some work).
|
||||
+ Remove =org/org-notebook=. It was unused and too small to warrant its own
|
||||
module. Useful tidbits were merged into =org/org=.
|
||||
+ =general=
|
||||
+ =Makefile=
|
||||
+ Fix ~make update~ to work even if Doom is installed somewhere other than
|
||||
~\~/.emacs.d~ (see [[https://github.com/hlissner/doom-emacs/issues/190][#190]]).
|
||||
+ Removed colons from makefile task target names (like =compile:core=);
|
||||
replaced them with dashses, e.g. =compile-core=. Colons broke compatibility
|
||||
with certain versions of make.
|
||||
+ =autoload=
|
||||
+ New library: =menu.el= -- allows context-sensitive and customizable
|
||||
fuzzy-searchable menus; this was written to replace long lists of
|
||||
major-mode-local key bindings, like refactoring and code building
|
||||
commands. This replaces =feature/eval='s build task system.
|
||||
+ =editor.el= Fix old scratch buffer commands and renamed them:
|
||||
~doom/open-scratch-buffer~ and ~doom/open-project-scratch-buffer~. The
|
||||
former opens a temporary, transient scratch buffer, the latter opens a
|
||||
permanent one tied to the current project, kept in
|
||||
~doom-scratch-files-dir~.
|
||||
+ =window.el= Changed ~doom-resize-window~ to accept two more arguments,
|
||||
=WINDOW= and =FORCE-P=: ~doom-resize-window WINDOW NEW-SIZE &optional
|
||||
HORIZONTAL FORCE-P~. If =FORCE-P= is non-nil, this function will resize a
|
||||
window regardless of ~window-size-fixed~.
|
||||
+ =core-keybinds= Add new =def-hydra!= alias macro for ~defhydra~ (for
|
||||
consistency, and in case we want to wrap it later).
|
||||
+ =core-projects= Redesign ~def-project-mode!~ for efficiency, and:
|
||||
+ The =:init FORM= property is now =:on-load FORM=.
|
||||
+ Three new properties: =:on-enter FORM=, =:on-exit FORM= and =:add-hooks
|
||||
LIST=.
|
||||
+ =core-popups=
|
||||
+ Added two new popup properties:
|
||||
+ ~:static~ If non-nil, treat this popup like a permanent window, making
|
||||
it impervious to automatic closing and being tracked in popup history.
|
||||
This is excellent for semi-permanent popups, like sidebars (think
|
||||
Neotree or imenu-list).
|
||||
+ ~:autofit~ If non-nil, this popup will resize to fit its buffer
|
||||
contents. This only works with popups where the buffer content is
|
||||
immediately available, and not for, say, buffers tied to async
|
||||
processes.
|
||||
+ ~doom-popup-buffer~ and ~doom-popup-file~ no longer take a variadic
|
||||
argument. Their signature is now ~doom-popup-buffer buffer plist &optional
|
||||
extend-p~ and ~doom-popup-file file plist &optional extend-p~, where
|
||||
=EXTEND-P= will cause =PLIST= to extend from the base rule for that
|
||||
buffer.
|
||||
+ Rename ~doom-popup-prop~ to ~doom-popup-property~.
|
||||
+ Add support for moving popup windows. See the ~doom/popup-move-*~
|
||||
commands. There are used by ~+evil/window-move-*~, which provides
|
||||
universal support for moving windows.
|
||||
+ Add command: ~doom/popup-raise~, for promoting a popup into a regular
|
||||
window.
|
||||
+ Add helper macro: ~save-popup! BODY~ -- hides the popups before running
|
||||
BODY.
|
||||
+ Fix ~doom/popup-toggle~ and ~save-popups!~ killing popups with an
|
||||
=:autokill= property.
|
||||
+ =feature=
|
||||
+ =hydra= Display a separator along the bottom of hydra windows for extra contrast.
|
||||
+ =hydra= Display a separator on the bottom of hydra windows for contrast.
|
||||
+ =eval= Build-task management has been removed from =feature/eval= in favor
|
||||
of ~def-menu!~.
|
||||
+ =ui=
|
||||
+ =doom-dashboard= Elements are now centered using window-local margins, which fixes discrepancies when multiple dashboards are visible in different sized windows and/or frames (see [[https://github.com/hlissner/doom-emacs/issues/192][#192]]).
|
||||
+ =doom-dashboard=
|
||||
+ Fix /horizontal/ centering discrepancies caused by multiple visible
|
||||
dashboards in windows/frames with different sizes (see [[https://github.com/hlissner/doom-emacs/issues/192][#192]]). Still
|
||||
doesn't address vertical centering.
|
||||
+ Fix dashboard's default-directory not changing to the last open project
|
||||
when switched to.
|
||||
+ =doom-modeline= Add a new style to ~+doom-modeline-buffer-file-name-style~:
|
||||
~relative-from-project~, which displays on the buffer's path relative to
|
||||
(and including) the project.
|
||||
+ =hl-todo= Add face-based detection for commented regions, so hl-todo can
|
||||
work in modes with no/poor syntax-table support.
|
||||
+ =tools=
|
||||
+ =neotree=
|
||||
+ Fix neotree shrinking by 1 when vertical splits were closed.
|
||||
+ Fix Neotree popup rule not taking ~neo-window-width~ and
|
||||
~neo-window-position~ into account.
|
||||
+ =term= Renamed commands for consistency (to ~+term/open~, ~+term/open-popup~
|
||||
and ~+term/open-popup-in-project~).
|
||||
+ =eshell= Renamed commands for consistency (to ~+eshell/open~,
|
||||
~+eshell/open-popup~ and ~+eshell/open-workspace~).
|
||||
+ =lang=
|
||||
+ =ruby= Add rake support. See the ~rake~ command.
|
||||
+ =web= Only install company-web if =:completion company= is enabled.
|
||||
+ =javascript=
|
||||
+ Add eslint_d and eslint_d-fix detection and support.
|
||||
+ =./node_modules/.bin= is now added to ~exec-path~ in NPM project buffers.
|
||||
+ =haskell= There is no longer a 'default' implementation for Haskell. The
|
||||
=+intero= and/or =+dante= module flags must be specified in init.el.
|
||||
+ =java= Meghanada is no longer the 'default' implementation for Java. The
|
||||
=+meghanada= and/or =+eclim= module flags must be specified in init.el.
|
||||
+ =org=
|
||||
+ If a table is under point when ~+org/toggle-fold~ is invoked, the table is realigned.
|
||||
+ =org-capture= Fix a vestigial reference to a long-since-renamed function: ~doom/project-root~.
|
||||
+ If a table is under point when ~+org/toggle-fold~ is invoked, the table is
|
||||
realigned.
|
||||
+ Fix the incorrect version of org being loaded (site, instead of ELPA) by
|
||||
pushing it up further in the ~load-path~.
|
||||
+ Fix ~+org/insert-item~ not jumping over sublists to append a new list item.
|
||||
|
||||
* 2.0.5 (Sep 03, 2017)
|
||||
+ =doom=
|
||||
@ -150,7 +194,7 @@
|
||||
+ Unit-tests have been moved to their respective modules (and =core/test/=).
|
||||
+ Fix ~def-setting!~ to act more like ~defmacro~; don't aggressively evaluate its arguments on expansion.
|
||||
+ New function: ~doom-set-buffer-real BUFFER FLAG~ -- makes Doom consider BUFFER real, no matter what.
|
||||
+ Add ~INSTALLED-ONLY-P~ argument to ~doom-get-packages~ to filter packages that aren't installed.
|
||||
+ Add INSTALLED-ONLY-P argument to ~doom-get-packages~ to filter packages that aren't installed.
|
||||
+ =core-ui=
|
||||
+ Add quit confirmation when trying to close a frame that contains real buffers.
|
||||
+ Fix quit confirmations for clients connected to ~emacs --daemon~ with ~emacsclient~.
|
||||
@ -170,7 +214,7 @@
|
||||
+ =core-packages=
|
||||
+ Generalize ~doom-package-*-p~ functions into ~(doom-package-prop NAME PROPERTY)~.
|
||||
+ Fix quelpa temporary files (in ~quelpa-build-dir~) not being removed when a quelpa package was uninstalled.
|
||||
+ New hook: ~doom-reload-hook~ (sort of). This has been around for a while, but now it is defined and documented. It runs when ~doom/reload~ is called (which gets called remotely if you run package management while an Emacs session is active).
|
||||
+ New hook: ~doom-reload-hook~ (sort of). This has been around for a while, but now it is defined and documented. It runs when ~doom/reload-load-path~ is called (which gets called remotely if you run package management while an Emacs session is active).
|
||||
+ ~load!~ can now accept a string as its first argument (the path).
|
||||
+ =feature=
|
||||
+ =feature/evil=
|
||||
@ -354,7 +398,7 @@
|
||||
+ =feature=
|
||||
+ =feature/eval=
|
||||
+ Fix ~:repl~ & ~+eval/repl-send-region~.
|
||||
+ Fix ~+eval/region~ failing only on first invocation because ~+eval-runners-alist~ wasn't populated until quickrun is loaded.
|
||||
+ Fix ~+eval/region~ failing only on first invocation because ~+eval-runners~ wasn't populated until quickrun is loaded.
|
||||
+ Add TAB auto-completion in comint-mode and REPL buffers
|
||||
+ =feature/evil=
|
||||
+ Fix ~:mv~ & ~:rm~.
|
||||
|
35
Makefile
35
Makefile
@ -7,6 +7,15 @@ MODULES=$(patsubst modules/%, %, $(shell find modules/ -maxdepth 2 -type d))
|
||||
|
||||
all: autoloads autoremove install
|
||||
|
||||
## Aliases
|
||||
a: autoloads
|
||||
i: install
|
||||
u: update
|
||||
r: autoremove
|
||||
c: compile
|
||||
cc: compile-core
|
||||
ce: compile-elpa
|
||||
|
||||
## Package management
|
||||
install: init.el .local/autoloads.el
|
||||
@$(EMACS) -f doom/packages-install
|
||||
@ -23,21 +32,21 @@ autoloads: init.el
|
||||
|
||||
## Byte compilation
|
||||
# compile
|
||||
# compile:core
|
||||
# compile:module
|
||||
# compile:module/submodule
|
||||
# compile-core
|
||||
# compile-module
|
||||
# compile-module/submodule
|
||||
compile: init.el clean
|
||||
@$(EMACS) -f doom/compile
|
||||
|
||||
compile\:core: init.el clean
|
||||
compile-core: init.el clean
|
||||
@$(EMACS) -f doom/compile -- init.el core
|
||||
|
||||
compile\:elpa: init.el
|
||||
compile-elpa: init.el
|
||||
@$(EMACS) -f doom/recompile-packages
|
||||
|
||||
$(patsubst %, compile\:%, $(MODULES)): init.el .local/autoloads.el
|
||||
@rm -fv $(shell find $(patsubst compile:%, modules/%, $@) -type f -name '*.elc')
|
||||
@$(EMACS) -f doom/compile -- $(patsubst compile:%, modules/%, $@)
|
||||
$(patsubst %, compile-%, $(MODULES)): init.el .local/autoloads.el
|
||||
@rm -fv $(shell find $(patsubst compile-%, modules/%, $@) -type f -name '*.elc')
|
||||
@$(EMACS) -f doom/compile -- $(patsubst compile-%, modules/%, $@)
|
||||
|
||||
recompile: init.el
|
||||
@$(EMACS) -f doom/recompile
|
||||
@ -54,14 +63,14 @@ reset:
|
||||
|
||||
## Unit tests
|
||||
# test
|
||||
# test:core
|
||||
# test:module
|
||||
# test:module/submodule
|
||||
# test-core
|
||||
# test-module
|
||||
# test-module/submodule
|
||||
test: init.el .local/autoloads.el
|
||||
@$(EMACS) -f doom-run-tests
|
||||
|
||||
test\:core $(patsubst %, test\:%, $(MODULES)): init.el .local/autoloads.el
|
||||
@$(EMACS) -f doom-run-tests -- $(subst test:, , $@)
|
||||
test-core $(patsubst %, test-%, $(MODULES)): init.el .local/autoloads.el
|
||||
@$(EMACS) -f doom-run-tests -- $(subst test-, , $@)
|
||||
|
||||
# run tests interactively
|
||||
testi: init.el .local/autoloads.el
|
||||
|
@ -9,20 +9,35 @@
|
||||
|
||||
set -e
|
||||
|
||||
key="${1:-n}"
|
||||
|
||||
cleanup() {
|
||||
emacsclient --eval '(kill-emacs)'
|
||||
}
|
||||
|
||||
# If emacs isn't running, we start a temporary daemon, solely for this window.
|
||||
daemon=
|
||||
if ! pgrep emacs >/dev/null; then
|
||||
emacs --daemon
|
||||
trap cleanup EXIT INT TERM
|
||||
daemon=1
|
||||
fi
|
||||
|
||||
# TODO Allow piping from stdin
|
||||
# org-capture key mapped to argument flags
|
||||
keys=$(emacsclient -e "(+org-capture-available-keys)" | cut -d '"' -f2)
|
||||
while getopts $keys opt; do
|
||||
key="\"$opt\""
|
||||
break
|
||||
done
|
||||
shift $((OPTIND-1))
|
||||
|
||||
emacsclient -c \
|
||||
-F '((name . "org-capture") (width . 70) (height . 25))' \
|
||||
--eval "(+org-capture/dwim \"$2\" \"$key\")"
|
||||
[ -t 0 ] && str="$*" || str=$(cat)
|
||||
|
||||
if [[ $daemon ]]; then
|
||||
emacsclient -a "" \
|
||||
-c -F '((name . "org-capture") (width . 70) (height . 25))' \
|
||||
-e "(+org-capture/open-frame \"$str\" ${key:-nil})"
|
||||
else
|
||||
# Non-daemon servers flicker a lot if frames are created from terminal, so
|
||||
# we do it internally instead.
|
||||
emacsclient -a "" \
|
||||
-e "(+org-capture/open-frame \"$str\" ${key:-nil})"
|
||||
fi
|
||||
|
@ -53,7 +53,7 @@ Inspired from http://demonastery.org/2013/04/emacs-evil-narrow-region/"
|
||||
|
||||
If no project is active, return all buffers."
|
||||
(let ((buffers (doom-buffer-list)))
|
||||
(if-let (project-root (doom-project-root t))
|
||||
(if-let (project-root (if (doom-project-p) (doom-project-root)))
|
||||
(cl-loop for buf in buffers
|
||||
if (projectile-project-buffer-p buf project-root)
|
||||
collect buf)
|
||||
@ -116,9 +116,9 @@ buffers. If there's nothing left, switch to `doom-fallback-buffer'. See
|
||||
(project-dir (doom-project-root)))
|
||||
(cond ((or (not buffers)
|
||||
(zerop (% n (1+ (length buffers)))))
|
||||
(set-window-buffer nil (doom-fallback-buffer)))
|
||||
(switch-to-buffer (doom-fallback-buffer) nil t))
|
||||
((= (length buffers) 1)
|
||||
(set-window-buffer nil (car buffers)))
|
||||
(switch-to-buffer (car buffers) nil t))
|
||||
(t
|
||||
;; Why this instead of switching straight to the Nth buffer in
|
||||
;; BUFFERS? Because `switch-to-next-buffer' and
|
||||
@ -136,9 +136,19 @@ buffers. If there's nothing left, switch to `doom-fallback-buffer'. See
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-real-buffer-p (&optional buffer-or-name)
|
||||
"Returns t if BUFFER-OR-NAME is a 'real' buffer. Real means it a) isn't a
|
||||
popup window/buffer and b) isn't a special buffer."
|
||||
(let ((buf (window-normalize-buffer buffer-or-name)))
|
||||
"Returns t if BUFFER-OR-NAME is a 'real' buffer. The complete criteria for a
|
||||
real buffer is:
|
||||
|
||||
1. The buffer-local value of `doom-real-buffer-p' (variable) is non-nil OR
|
||||
2. Any function in `doom-real-buffer-functions' must return non-nil when
|
||||
passed this buffer OR
|
||||
3. The current buffer:
|
||||
a) has a `buffer-file-name' defined AND
|
||||
b) is not in a popup window (see `doom-popup-p') AND
|
||||
c) is not a special buffer (its name isn't something like *Help*)
|
||||
|
||||
If BUFFER-OR-NAME is omitted or nil, the current buffer is tested."
|
||||
(when-let (buf (ignore-errors (window-normalize-buffer buffer-or-name)))
|
||||
(or (buffer-local-value 'doom-real-buffer-p buf)
|
||||
(run-hook-with-args-until-success 'doom-real-buffer-functions buf)
|
||||
(not (or (doom-popup-p buf)
|
||||
@ -148,14 +158,14 @@ popup window/buffer and b) isn't a special buffer."
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/next-buffer ()
|
||||
"Switch to the next real buffer, skipping special buffers. See
|
||||
"Switch to the next real buffer, skipping non-real buffers. See
|
||||
`doom-real-buffer-p' for what 'real' means."
|
||||
(interactive)
|
||||
(doom--cycle-real-buffers +1))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/previous-buffer ()
|
||||
"Switch to the previous real buffer, skipping special buffers. See
|
||||
"Switch to the previous real buffer, skipping non-real buffers. See
|
||||
`doom-real-buffer-p' for what 'real' means."
|
||||
(interactive)
|
||||
(doom--cycle-real-buffers -1))
|
||||
@ -163,7 +173,10 @@ popup window/buffer and b) isn't a special buffer."
|
||||
;;;###autoload
|
||||
(defun doom-kill-buffer (&optional buffer dont-save)
|
||||
"Kill BUFFER (falls back to current buffer if omitted) then switch to a real
|
||||
buffer, but only bury the buffer if it is present in another window.
|
||||
buffer. If the buffer is present in another window, only bury it.
|
||||
|
||||
Will prompt to save unsaved buffers when attempting to kill them, unless
|
||||
DONT-SAVE is non-nil.
|
||||
|
||||
See `doom-real-buffer-p' for what 'real' means."
|
||||
(setq buffer (or buffer (current-buffer)))
|
||||
@ -250,10 +263,12 @@ regex PATTERN. Returns the number of killed buffers."
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/kill-all-buffers (&optional project-p)
|
||||
"Kill all buffers.
|
||||
"Kill all buffers and closes their windows.
|
||||
|
||||
If PROJECT-P, kill all buffers that belong to the current project."
|
||||
If PROJECT-P (universal argument), kill only buffers that belong to the current
|
||||
project."
|
||||
(interactive "P")
|
||||
(doom/popup-kill-all)
|
||||
(let ((buffers (if project-p (doom-project-buffer-list) (doom-buffer-list))))
|
||||
(mapc #'doom-kill-buffer-and-windows buffers)
|
||||
(unless (doom-real-buffer-p)
|
||||
@ -262,10 +277,10 @@ If PROJECT-P, kill all buffers that belong to the current project."
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/kill-other-buffers (&optional project-p)
|
||||
"Kill all other buffers.
|
||||
"Kill all other buffers (besides the current one).
|
||||
|
||||
If PROJECT-P (universal argument), kill only the other buffers that belong to
|
||||
the current project."
|
||||
If PROJECT-P (universal argument), kill only buffers that belong to the current
|
||||
project."
|
||||
(interactive "P")
|
||||
(let ((buffers (if project-p (doom-project-buffer-list) (doom-buffer-list)))
|
||||
(current-buffer (current-buffer)))
|
||||
@ -291,7 +306,7 @@ project."
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/cleanup-buffers (&optional all-p)
|
||||
"Clean up buried and process buffers in the current workspace."
|
||||
"Clean up buried and inactive process buffers in the current workspace."
|
||||
(interactive "P")
|
||||
(let ((buffers (doom-buried-buffers (if all-p (buffer-list))))
|
||||
(n 0))
|
||||
|
@ -7,18 +7,13 @@
|
||||
Interactively prints the list to the echo area. Noninteractively, returns a list
|
||||
whose car is the list of faces and cadr is the list of overlay faces."
|
||||
(interactive)
|
||||
(unless pos
|
||||
(setq pos (point)))
|
||||
(let ((faces (let ((face (get-text-property pos 'face)))
|
||||
(let* ((pos (or pos (point)))
|
||||
(faces (let ((face (get-text-property pos 'face)))
|
||||
(if (keywordp (car-safe face))
|
||||
(list face)
|
||||
(cl-loop for f in (if (listp face) face (list face))
|
||||
collect f))))
|
||||
(cl-loop for f in (doom-enlist face) collect f))))
|
||||
(overlays (cl-loop for ov in (overlays-at pos (1+ pos))
|
||||
nconc (cl-loop with face = (overlay-get ov 'face)
|
||||
for f in (if (listp face) face (list face))
|
||||
collect f))))
|
||||
|
||||
nconc (doom-enlist (overlay-get ov 'face)))))
|
||||
(cond ((called-interactively-p 'any)
|
||||
(message "%s %s\n%s %s"
|
||||
(propertize "Faces:" 'face 'font-lock-comment-face)
|
||||
@ -63,6 +58,8 @@ selection of all minor-modes, active or not."
|
||||
"Test to see if your root certificates are securely configured in emacs."
|
||||
(declare (interactive-only t))
|
||||
(interactive)
|
||||
(unless (string-match-p "\\_<GNUTLS\\_>" system-configuration-features)
|
||||
(warn "gnutls support isn't built into Emacs, there may be problems"))
|
||||
(if-let (bad-hosts
|
||||
(cl-loop for bad
|
||||
in '("https://wrong.host.badssl.com/"
|
||||
|
@ -15,21 +15,19 @@
|
||||
(interactive)
|
||||
(doom/sudo-find-file (file-truename buffer-file-name)))
|
||||
|
||||
(defun doom--goto-first-non-blank ()
|
||||
(beginning-of-visual-line)
|
||||
(skip-chars-forward " \t\r"))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/backward-to-bol-or-indent ()
|
||||
"Move back to the current line's indentation. If already there, move to the
|
||||
beginning of the line instead. If at bol, do nothing."
|
||||
(interactive)
|
||||
(let ((boi (save-excursion (back-to-indentation) (point)))
|
||||
(point (point)))
|
||||
(if (= boi point)
|
||||
(if (bound-and-true-p visual-line-mode)
|
||||
(beginning-of-visual-line)
|
||||
(unless (= (line-beginning-position) point)
|
||||
(doom--goto-first-non-blank)))))
|
||||
(let ((ci (current-indentation))
|
||||
(cc (current-column)))
|
||||
(cond ((or (> cc ci) (= cc 0))
|
||||
(back-to-indentation))
|
||||
((<= cc ci)
|
||||
(beginning-of-visual-line))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/forward-to-last-non-comment-or-eol ()
|
||||
@ -80,22 +78,28 @@ If already there, do nothing."
|
||||
(interactive)
|
||||
(if indent-tabs-mode
|
||||
(call-interactively #'backward-delete-char)
|
||||
(unless (bolp)
|
||||
(save-excursion
|
||||
(unless (looking-back "^[\s\t]*" (line-beginning-position))
|
||||
(doom--goto-first-non-blank))
|
||||
(let* ((movement (% (current-column) tab-width))
|
||||
(spaces (if (= 0 movement) tab-width (- tab-width movement))))
|
||||
(delete-char (- spaces))))))
|
||||
(when (> (current-column) (current-indentation))
|
||||
(back-to-indentation))
|
||||
(let ((movement (% (current-column) tab-width)))
|
||||
(delete-char
|
||||
(- (if (= 0 movement)
|
||||
tab-width
|
||||
(- tab-width movement)))))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/backward-kill-to-bol-and-indent ()
|
||||
"Kill line to the first non-blank character. If invoked again
|
||||
afterwards, kill line to column 1."
|
||||
(interactive)
|
||||
(let ((empty-line (save-excursion (beginning-of-line) (looking-at-p "[ \t]*$"))))
|
||||
(funcall (if (featurep 'evil) #'evil-delete #'delete-region)
|
||||
(let ((empty-line-p (save-excursion (beginning-of-line)
|
||||
(looking-at-p "[ \t]*$"))))
|
||||
(funcall (if (featurep 'evil)
|
||||
#'evil-delete
|
||||
#'delete-region)
|
||||
(point-at-bol) (point))
|
||||
(unless empty-line
|
||||
(unless empty-line-p
|
||||
(indent-according-to-mode))))
|
||||
|
||||
;;;###autoload
|
||||
@ -131,7 +135,9 @@ possible, or just one char if that's not possible."
|
||||
(save-match-data
|
||||
(if (string-match "\\w*\\(\\s-+\\)$"
|
||||
(buffer-substring-no-properties (max (point-min) (- p movement)) p))
|
||||
(sp-delete-char (- 0 (- (match-end 1) (match-beginning 1))))
|
||||
(sp-delete-char
|
||||
(- 0 (- (match-end 1)
|
||||
(match-beginning 1))))
|
||||
(call-interactively delete-backward-char)))))
|
||||
|
||||
;; Otherwise do a regular delete
|
||||
@ -157,18 +163,19 @@ spaces on either side of the point if so. Resorts to
|
||||
`doom/backward-delete-whitespace-to-column' otherwise."
|
||||
(interactive)
|
||||
(save-match-data
|
||||
(cond ((doom--surrounded-p)
|
||||
(if (doom--surrounded-p)
|
||||
(let ((whitespace-match (match-string 1)))
|
||||
(cond ((not whitespace-match)
|
||||
(call-interactively #'delete-backward-char))
|
||||
((string-match "\n" whitespace-match)
|
||||
(funcall (if (featurep 'evil) #'evil-delete #'delete-region)
|
||||
(funcall (if (featurep 'evil)
|
||||
#'evil-delete
|
||||
#'delete-region)
|
||||
(point-at-bol) (point))
|
||||
(call-interactively #'delete-backward-char)
|
||||
(save-excursion (call-interactively #'delete-char)))
|
||||
(t (just-one-space 0)))))
|
||||
(t
|
||||
(doom/backward-delete-whitespace-to-column)))))
|
||||
(t (just-one-space 0))))
|
||||
(doom/backward-delete-whitespace-to-column))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/newline-and-indent ()
|
||||
@ -179,15 +186,16 @@ with weak native support."
|
||||
(cond ((sp-point-in-string)
|
||||
(newline))
|
||||
((sp-point-in-comment)
|
||||
(cond ((memq major-mode '(js2-mode rjsx-mode))
|
||||
(pcase major-mode
|
||||
((or 'js2-mode 'rjsx-mode)
|
||||
(call-interactively #'js2-line-break))
|
||||
((memq major-mode '(java-mode php-mode))
|
||||
((or 'java-mode 'php-mode)
|
||||
(c-indent-new-comment-line))
|
||||
((memq major-mode '(c-mode c++-mode objc-mode css-mode scss-mode js2-mode))
|
||||
((or 'c-mode 'c++-mode 'objc-mode 'css-mode 'scss-mode 'js2-mode)
|
||||
(newline-and-indent)
|
||||
(insert "* ")
|
||||
(indent-according-to-mode))
|
||||
(t
|
||||
(_
|
||||
;; Fix an off-by-one cursor-positioning issue
|
||||
;; with `indent-new-comment-line'
|
||||
(let ((col (save-excursion (comment-beginning) (current-column))))
|
||||
@ -210,47 +218,8 @@ consistent throughout a selected region, depending on `indent-tab-mode'."
|
||||
(tabify beg end)
|
||||
(untabify beg end)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/toggle-sticky (&optional beg end)
|
||||
"Make a selection sticky by placing it in the header line. Possibly helpful
|
||||
for function signatures or notes. Run again to clear the header line."
|
||||
(interactive "r")
|
||||
(setq header-line-format
|
||||
(when mark-active
|
||||
(concat (propertize (format linum-format (line-number-at-pos beg))
|
||||
'face 'font-lock-comment-face)
|
||||
(let ((content (buffer-substring beg end)))
|
||||
(setq content (replace-regexp-in-string "\n" " " content t t))
|
||||
(setq content (replace-regexp-in-string "\\s-+" " " content))
|
||||
content)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/scratch-buffer (&optional arg)
|
||||
"Opens the scratch buffer in a popup window.
|
||||
|
||||
If ARG (universal argument) is non-nil, open it in the current window instead of
|
||||
a popup.
|
||||
|
||||
If a region is active, copy it into the scratch buffer."
|
||||
(interactive "P")
|
||||
(let ((text (and (region-active-p)
|
||||
(buffer-substring-no-properties
|
||||
(region-beginning) (region-end))))
|
||||
(mode major-mode)
|
||||
(derived-p (derived-mode-p 'prog-mode 'text-mode))
|
||||
(old-project (doom-project-root))
|
||||
(new-buf (get-buffer-create "*doom:scratch*")))
|
||||
(if arg
|
||||
(switch-to-buffer new-buf)
|
||||
(doom-popup-buffer new-buf))
|
||||
(with-current-buffer new-buf
|
||||
(setq default-directory old-project)
|
||||
(when (and (not (eq major-mode mode))
|
||||
derived-p
|
||||
(functionp mode))
|
||||
(funcall mode))
|
||||
(if text (insert text)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom|enable-delete-trailing-whitespace ()
|
||||
"Attaches `delete-trailing-whitespace' to a buffer-local `before-save-hook'."
|
||||
(add-hook 'before-save-hook #'delete-trailing-whitespace nil t))
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
(interactive
|
||||
;; TODO try to read setting from whole line
|
||||
(list (completing-read "Describe setting%s: "
|
||||
(mapcar #'car doom-settings)
|
||||
(sort (mapcar #'car doom-settings) #'string-lessp)
|
||||
nil t nil nil)))
|
||||
(let ((fn (cdr (assq (intern setting) doom-settings))))
|
||||
(unless fn
|
||||
|
104
core/autoload/menu.el
Normal file
104
core/autoload/menu.el
Normal file
@ -0,0 +1,104 @@
|
||||
;;; ../core/autoload/menu.el -*- lexical-binding: t; -*-
|
||||
|
||||
;; Command dispatchers: basically M-x, but context sensitive, customizable and
|
||||
;; persistent across Emacs sessions.
|
||||
|
||||
(defvar doom-menu-display-fn #'doom-menu-read-default
|
||||
"The method to use to prompt the user with the menu. This takes two arguments:
|
||||
PROMPT (a string) and COMMAND (a list of command plists; see `def-menu!').")
|
||||
|
||||
(defun doom-menu-read-default (prompt commands)
|
||||
"Default method for displaying a completion-select prompt."
|
||||
(completing-read prompt (mapcar #'car commands)))
|
||||
|
||||
(defun doom--menu-read (prompt commands)
|
||||
(if-let (choice (funcall doom-menu-display-fn prompt commands))
|
||||
(cdr (assoc choice commands))
|
||||
(user-error "Aborted")))
|
||||
|
||||
(defun doom--menu-exec (plist)
|
||||
(let ((command (plist-get plist :exec))
|
||||
(cwd (plist-get plist :cwd)))
|
||||
(let ((default-directory
|
||||
(cond ((eq cwd t) (doom-project-root))
|
||||
((stringp cwd) cwd)
|
||||
(t default-directory))))
|
||||
(cond ((stringp command)
|
||||
(with-current-buffer (get-buffer-create "*compilation*")
|
||||
(setq command (doom-resolve-vim-path command))
|
||||
(save-window-excursion
|
||||
(compile command))
|
||||
(setq header-line-format
|
||||
(concat (propertize "$ " 'face 'font-lock-doc-face)
|
||||
(propertize command 'face 'font-lock-preprocessor-face)))
|
||||
(doom-resize-window
|
||||
(doom-popup-buffer (current-buffer)
|
||||
'(:autokill t :autoclose t)) 12)))
|
||||
((or (symbolp command)
|
||||
(functionp command))
|
||||
(call-interactively command))
|
||||
((and command (listp command))
|
||||
(eval command t))
|
||||
(t
|
||||
(error "Not a valid command: %s" command))))))
|
||||
|
||||
;;;###autoload
|
||||
(defmacro def-menu! (name desc commands &rest plist)
|
||||
"Defines a menu and returns a function symbol for invoking it.
|
||||
|
||||
A dispatcher is an interactive command named NAME (a symbol). When called, this
|
||||
dispatcher prompts you to select a command to run. This list is filtered
|
||||
depending on its properties. Each command is takes the form of:
|
||||
|
||||
(DESCRIPTION :exec COMMAND &rest PROPERTIES)
|
||||
|
||||
PROPERTIES accepts the following properties:
|
||||
|
||||
:when FORM
|
||||
:unless FORM
|
||||
:region BOOL
|
||||
:cwd t|PATH
|
||||
:project BOOL|DIRECTORY
|
||||
|
||||
COMMAND can be a string (a shell command), a symbol (an elisp function) or a
|
||||
lisp form.
|
||||
|
||||
`def-menu!'s PLIST supports the following properties:
|
||||
|
||||
:prompt STRING"
|
||||
(declare (indent defun) (doc-string 2))
|
||||
(let ((commands-var (intern (format "%s-commands" name)))
|
||||
(prop-prompt (or (plist-get plist :prompt) "> "))
|
||||
(prop-sort (plist-get plist :sort)))
|
||||
`(progn
|
||||
(defvar ,commands-var
|
||||
,(if prop-sort
|
||||
`(cl-sort ,commands #'string-lessp :key #'car)
|
||||
commands)
|
||||
,(format "Menu for %s" name))
|
||||
(defun ,name ()
|
||||
,desc
|
||||
(interactive)
|
||||
(unless ,commands-var
|
||||
(user-error "The '%s' menu is empty" ',name))
|
||||
(doom--menu-exec
|
||||
(or (doom--menu-read
|
||||
,prop-prompt
|
||||
(or (cl-remove-if-not
|
||||
(let ((project-root (doom-project-root)))
|
||||
(lambda (cmd)
|
||||
(let ((plist (cdr cmd)))
|
||||
(and (cond ((not (plist-member plist :region)) t)
|
||||
((plist-get plist :region) (use-region-p))
|
||||
(t (not (use-region-p))))
|
||||
(let ((when (plist-get plist :when))
|
||||
(unless (plist-get plist :unless))
|
||||
(project (plist-get plist :project)))
|
||||
(or (or (not when) (eval when))
|
||||
(or (not unless) (not (eval unless)))
|
||||
(and (stringp project)
|
||||
(file-in-directory-p buffer-file-name project-root))))))))
|
||||
,commands-var)
|
||||
(user-error "No commands available here")))
|
||||
(user-error "No command selected")))))))
|
||||
|
@ -354,7 +354,7 @@ package.el as appropriate."
|
||||
"")))))
|
||||
|
||||
(message! (bold (green "Finished!")))
|
||||
(doom/reload))))
|
||||
(doom/reload-load-path))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/packages-update ()
|
||||
@ -395,7 +395,7 @@ package.el as appropriate."
|
||||
(if result "DONE" "FAILED"))))))
|
||||
|
||||
(message! (bold (green "Finished!")))
|
||||
(doom/reload)))))
|
||||
(doom/reload-load-path)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/packages-autoremove ()
|
||||
@ -428,7 +428,7 @@ package.el as appropriate."
|
||||
pkg)))))
|
||||
|
||||
(message! (bold (green "Finished!")))
|
||||
(doom/reload)))))
|
||||
(doom/reload-load-path)))))
|
||||
|
||||
;;;###autoload
|
||||
(defalias 'doom/install-package #'package-install)
|
||||
|
@ -1,158 +1,95 @@
|
||||
;;; core/autoload/popups.el -*- lexical-binding: t; -*-
|
||||
|
||||
(defvar doom-popup-remember-history)
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-popup-p (&optional target)
|
||||
"Return TARGET (a window) if TARGET (a window or buffer) is a popup. Uses
|
||||
current window if omitted."
|
||||
"Return t if TARGET (a window or buffer) is a popup. Uses current window if
|
||||
omitted."
|
||||
(when-let (target (or target (selected-window)))
|
||||
(cond ((bufferp target)
|
||||
(buffer-local-value 'doom-popup-mode target))
|
||||
(and (buffer-live-p target)
|
||||
(buffer-local-value 'doom-popup-mode target)))
|
||||
((windowp target)
|
||||
(and (window-parameter target 'popup)
|
||||
target)))))
|
||||
(and (window-live-p target)
|
||||
(window-parameter target 'popup))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-popup-buffer (buffer &rest plist)
|
||||
"Display BUFFER in a shackle popup. See `shackle-rules' for possible rules.
|
||||
Returns the new popup window."
|
||||
(defun doom-popup-buffer (buffer &optional plist extend-p)
|
||||
"Display BUFFER in a shackle popup with PLIST rules. See `shackle-rules' for
|
||||
possible rules. If EXTEND-P is non-nil, don't overwrite the original rules for
|
||||
this popup, just the specified properties. Returns the new popup window."
|
||||
(declare (indent defun))
|
||||
(unless (bufferp buffer)
|
||||
(error "%s is not a valid buffer" buffer))
|
||||
(setq plist (append plist (shackle-match buffer)))
|
||||
(shackle-display-buffer
|
||||
buffer
|
||||
nil (or plist (shackle-match buffer))))
|
||||
nil (or (if extend-p
|
||||
(append plist (shackle-match buffer))
|
||||
plist)
|
||||
(shackle-match buffer))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-popup-switch-to-buffer (buffer)
|
||||
"Switch the current (or closest) pop-up window to BUFFER."
|
||||
(unless (doom-popup-p)
|
||||
(let ((popups (doom-popup-windows)))
|
||||
(unless popups
|
||||
(error "No popups to switch"))
|
||||
(select-window (car popups))))
|
||||
(if-let (popups (doom-popup-windows))
|
||||
(select-window (car popups))
|
||||
(error "No popups to switch to")))
|
||||
(set-window-dedicated-p nil nil)
|
||||
(switch-to-buffer buffer nil t)
|
||||
(prog1 (selected-window)
|
||||
(set-window-dedicated-p nil t)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-popup-file (file &rest plist)
|
||||
(defun doom-popup-fit-to-buffer (&optional window max-size)
|
||||
"Fit WINDOW to the size of its content."
|
||||
(unless (string-empty-p (buffer-string))
|
||||
(let* ((window-size (doom-popup-size window))
|
||||
(max-size (or max-size (doom-popup-property :size window)))
|
||||
(size (+ 2 (if (floatp max-size) (truncate (* max-size window-size)) window-size))))
|
||||
(fit-window-to-buffer window size nil size))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-popup-move (direction)
|
||||
"Move a popup window to another side of the frame, in DIRECTION, which can be
|
||||
one of the following: 'left 'right 'above 'below"
|
||||
(when (doom-popup-p)
|
||||
(let ((buffer (current-buffer))
|
||||
(doom-popup-inhibit-autokill t))
|
||||
(doom/popup-close)
|
||||
(doom-popup-buffer buffer `(:align ,direction) 'extend))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-popup-file (file &optional plist extend-p)
|
||||
"Display FILE in a shackle popup, with PLIST rules. See `shackle-rules' for
|
||||
possible rules."
|
||||
(unless (file-exists-p file)
|
||||
(user-error "Can't display file in popup, it doesn't exist: %s" file))
|
||||
(doom-popup-buffer (find-file-noselect file t) plist))
|
||||
(doom-popup-buffer (find-file-noselect file t) plist extend-p))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-popup-windows ()
|
||||
(defun doom-popup-windows (&optional filter-static-p)
|
||||
"Get a list of open pop up windows."
|
||||
(cl-remove-if-not #'doom-popup-p doom-popup-windows))
|
||||
(cl-loop for window in doom-popup-windows
|
||||
if (and (doom-popup-p window)
|
||||
(not (and filter-static-p
|
||||
(doom-popup-property :static window))))
|
||||
collect window))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/popup-restore ()
|
||||
"Restore the last open popups. If the buffers have been killed, and
|
||||
represented real files, they will be restored. Dead special buffers or buffers
|
||||
with non-nil :autokill properties will not be.
|
||||
|
||||
Returns t if popups were restored, nil otherwise."
|
||||
(interactive)
|
||||
(unless doom-popup-history
|
||||
(error "No popups to restore"))
|
||||
(let (any-p)
|
||||
(dolist (spec doom-popup-history)
|
||||
(let ((buffer (get-buffer (car spec)))
|
||||
(file (plist-get (cdr spec) :file))
|
||||
(rules (plist-get (cdr spec) :rules))
|
||||
(size (plist-get (cdr spec) :size)))
|
||||
(when (and (not buffer) file)
|
||||
(setq buffer
|
||||
(if-let (buf (get-file-buffer file))
|
||||
(clone-indirect-buffer (buffer-name buf) nil t)
|
||||
(find-file-noselect file t))))
|
||||
(when size
|
||||
(setq rules (plist-put rules :size size)))
|
||||
(when (and buffer (apply #'doom-popup-buffer buffer rules) (not any-p))
|
||||
(setq any-p t))))
|
||||
(when any-p
|
||||
(setq doom-popup-history '()))
|
||||
any-p))
|
||||
(defun doom-popup-properties (window-or-buffer)
|
||||
"Returns a window's popup property list, if possible. The buffer-local
|
||||
`doom-popup-rules' always takes priority, but this will fall back to the popup
|
||||
window parameter."
|
||||
(cond ((windowp window-or-buffer)
|
||||
(or (window-parameter window-or-buffer 'popup)
|
||||
(doom-popup-properties (window-buffer window-or-buffer))))
|
||||
((bufferp window-or-buffer)
|
||||
(buffer-local-value 'doom-popup-rules window-or-buffer))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/popup-toggle ()
|
||||
"Toggle popups."
|
||||
(interactive)
|
||||
(when (doom-popup-p)
|
||||
(if doom-popup-other-window
|
||||
(select-window doom-popup-other-window)
|
||||
(other-window 1)))
|
||||
(if (doom-popup-windows)
|
||||
(doom/popup-close-all t)
|
||||
(doom/popup-restore)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/popup-close (&optional window)
|
||||
"Find and close WINDOW if it's a popup. If WINDOW is omitted, defaults to
|
||||
`selected-window'. The contained buffer is buried, unless it has an :autokill
|
||||
property."
|
||||
(interactive)
|
||||
(when-let (window (doom-popup-p window))
|
||||
(delete-window window)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/popup-close-all (&optional force-p)
|
||||
"Closes all open popups. If FORCE-P is non-nil, or this function is called
|
||||
interactively, it will close all popups without question. Otherwise, it will
|
||||
only close popups that have an :autoclose property in their rule (see
|
||||
`shackle-rules')."
|
||||
(interactive)
|
||||
(when-let (popups (doom-popup-windows))
|
||||
(let (success doom-popup-remember-history)
|
||||
(setq doom-popup-history (mapcar #'doom--popup-data popups))
|
||||
(dolist (window popups)
|
||||
(when (or force-p
|
||||
(called-interactively-p 'interactive)
|
||||
(doom-popup-prop :autoclose window))
|
||||
(delete-window window)
|
||||
(setq success t)))
|
||||
success)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/popup-close-maybe ()
|
||||
"Close the current popup *if* its window doesn't have a noesc parameter."
|
||||
(interactive)
|
||||
(if (doom-popup-prop :noesc)
|
||||
(call-interactively
|
||||
(if (featurep 'evil)
|
||||
#'evil-force-normal-state
|
||||
#'keyboard-escape-quit))
|
||||
(delete-window)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/popup-this-buffer ()
|
||||
"Display currently selected buffer in a popup window."
|
||||
(interactive)
|
||||
(doom-popup-buffer (current-buffer) :align t :autokill t))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/popup-toggle-messages ()
|
||||
"Toggle *Messages* buffer."
|
||||
(interactive)
|
||||
(if-let (win (get-buffer-window "*Messages*"))
|
||||
(doom/popup-close win)
|
||||
(doom-popup-buffer (get-buffer "*Messages*"))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-popup-prop (prop &optional window)
|
||||
(defun doom-popup-property (prop &optional window)
|
||||
"Returns a `doom-popup-rules' PROPerty from WINDOW."
|
||||
(or (plist-get (or (if window
|
||||
(ignore-errors
|
||||
(buffer-local-value 'doom-popup-rules
|
||||
(window-buffer window)))
|
||||
doom-popup-rules)
|
||||
(window-parameter window 'popup))
|
||||
(or (plist-get (doom-popup-properties (or window (selected-window)))
|
||||
prop)
|
||||
(pcase prop
|
||||
(:size shackle-default-size)
|
||||
@ -161,7 +98,7 @@ only close popups that have an :autoclose property in their rule (see
|
||||
;;;###autoload
|
||||
(defun doom-popup-side (&optional window)
|
||||
"Return what side a popup WINDOW came from ('left 'right 'above or 'below)."
|
||||
(let ((align (doom-popup-prop :align window)))
|
||||
(let ((align (doom-popup-property :align window)))
|
||||
(when (eq align t)
|
||||
(setq align shackle-default-alignment))
|
||||
(when (functionp align)
|
||||
@ -186,11 +123,137 @@ only close popups that have an :autoclose property in their rule (see
|
||||
(defmacro with-popup-rules! (rules &rest body)
|
||||
"TODO"
|
||||
(declare (indent defun))
|
||||
`(let ((old-shackle-rules shackle-rules))
|
||||
`(let (shackle-rules)
|
||||
,@(cl-loop for rule in rules
|
||||
collect `(set! :popup ,@rule))
|
||||
,@body
|
||||
(setq shackle-rules old-shackle-rules)))
|
||||
,@body))
|
||||
|
||||
;;;###autoload
|
||||
(defmacro save-popups! (&rest body)
|
||||
"Sets aside all popups before executing the original function, usually to
|
||||
prevent the popup(s) from messing up the UI (or vice versa)."
|
||||
`(let ((in-popup-p (doom-popup-p))
|
||||
(popups (doom-popup-windows))
|
||||
(doom-popup-remember-history t)
|
||||
(doom-popup-inhibit-autokill t))
|
||||
(when popups
|
||||
(mapc #'doom/popup-close popups))
|
||||
(unwind-protect
|
||||
(progn ,@body)
|
||||
(when popups
|
||||
(let ((origin (selected-window)))
|
||||
(doom/popup-restore)
|
||||
(unless in-popup-p
|
||||
(select-window origin)))))))
|
||||
|
||||
|
||||
;; --- Commands ---------------------------
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/popup-restore ()
|
||||
"Restore the last open popups. If the buffers have been killed, and
|
||||
represented real files, they will be restored. Dead special buffers or buffers
|
||||
with non-nil :autokill properties will not be.
|
||||
|
||||
Returns t if popups were restored, nil otherwise."
|
||||
(interactive)
|
||||
(unless doom-popup-history
|
||||
(error "No popups to restore"))
|
||||
(let (any-p)
|
||||
(dolist (spec doom-popup-history)
|
||||
(let ((buffer (get-buffer (car spec)))
|
||||
(file (plist-get (cdr spec) :file))
|
||||
(rules (plist-get (cdr spec) :rules))
|
||||
(size (plist-get (cdr spec) :size)))
|
||||
(when (and (not buffer) file)
|
||||
(setq buffer
|
||||
(if-let (buf (get-file-buffer file))
|
||||
(clone-indirect-buffer (buffer-name buf) nil t)
|
||||
(find-file-noselect file t))))
|
||||
(when size
|
||||
(setq rules (plist-put rules :size size)))
|
||||
(when (and buffer (doom-popup-buffer buffer rules) (not any-p))
|
||||
(setq any-p t))))
|
||||
(when any-p
|
||||
(setq doom-popup-history '()))
|
||||
any-p))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/popup-toggle ()
|
||||
"Toggle popups on and off. If used outside of popups (and popups are
|
||||
available), it will select the nearest popup window."
|
||||
(interactive)
|
||||
(when (doom-popup-p)
|
||||
(if doom-popup-other-window
|
||||
(select-window doom-popup-other-window)
|
||||
(other-window 1)))
|
||||
(if (doom-popup-windows t)
|
||||
(let ((doom-popup-inhibit-autokill t))
|
||||
(doom/popup-close-all t))
|
||||
(doom/popup-restore)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/popup-close (&optional window)
|
||||
"Find and close WINDOW if it's a popup. If WINDOW is omitted, defaults to
|
||||
`selected-window'. The contained buffer is buried, unless it has an :autokill
|
||||
property."
|
||||
(interactive)
|
||||
(when (doom-popup-p window)
|
||||
(delete-window (or window (selected-window)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/popup-close-all (&optional force-p)
|
||||
"Closes most open popups.
|
||||
|
||||
Does not close popups that are :static or don't have an :autoclose property (see
|
||||
`shackle-rules').
|
||||
|
||||
If FORCE-P is non-nil (or this function is called interactively), ignore popups'
|
||||
:autoclose property. This command will never close :static popups."
|
||||
(interactive
|
||||
(list (called-interactively-p 'interactive)))
|
||||
(when-let (popups (doom-popup-windows t))
|
||||
(let (success doom-popup-remember-history)
|
||||
(setq doom-popup-history (delq nil (mapcar #'doom--popup-data popups)))
|
||||
(dolist (window popups success)
|
||||
(when (or force-p (doom-popup-property :autoclose window))
|
||||
(delete-window window)
|
||||
(setq success t))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/popup-kill-all ()
|
||||
"Like `doom/popup-close-all', but kill *all* popups, including :static ones,
|
||||
without leaving any trace behind (muahaha)."
|
||||
(interactive)
|
||||
(when-let (popups (doom-popup-windows))
|
||||
(let (doom-popup-remember-history)
|
||||
(setq doom-popup-history nil)
|
||||
(mapc #'delete-window popups))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/popup-close-maybe ()
|
||||
"Close the current popup *if* its window doesn't have a noesc parameter."
|
||||
(interactive)
|
||||
(if (doom-popup-property :noesc)
|
||||
(call-interactively
|
||||
(if (featurep 'evil)
|
||||
#'evil-force-normal-state
|
||||
#'keyboard-escape-quit))
|
||||
(delete-window)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/popup-this-buffer ()
|
||||
"Display currently selected buffer in a popup window."
|
||||
(interactive)
|
||||
(doom-popup-buffer (current-buffer) '(:align t :autokill t)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/popup-toggle-messages ()
|
||||
"Toggle *Messages* buffer."
|
||||
(interactive)
|
||||
(if-let (win (get-buffer-window "*Messages*"))
|
||||
(doom/popup-close win)
|
||||
(doom-popup-buffer (get-buffer "*Messages*"))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/other-popup (count)
|
||||
@ -207,3 +270,155 @@ only close popups that have an :autoclose property in their rule (see
|
||||
(cl-decf count))
|
||||
(when (/= count 0)
|
||||
(other-window count)))))
|
||||
|
||||
;;;###autoload
|
||||
(defalias 'other-popup #'doom/other-popup)
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/popup-raise (&optional window)
|
||||
"Turn a popup window into a normal window."
|
||||
(interactive)
|
||||
(let ((window (or window (selected-window))))
|
||||
(unless (doom-popup-p window)
|
||||
(user-error "Not a valid popup to raise"))
|
||||
(with-selected-window window
|
||||
(doom-popup-mode -1))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/popup-move-top () "See `doom-popup-move'." (interactive) (doom-popup-move 'above))
|
||||
;;;###autoload
|
||||
(defun doom/popup-move-bottom () "See `doom-popup-move'." (interactive) (doom-popup-move 'below))
|
||||
;;;###autoload
|
||||
(defun doom/popup-move-left () "See `doom-popup-move'." (interactive) (doom-popup-move 'left))
|
||||
;;;###autoload
|
||||
(defun doom/popup-move-right () "See `doom-popup-move'." (interactive) (doom-popup-move 'right))
|
||||
|
||||
|
||||
;; --- doom-popup-mode --------------------
|
||||
|
||||
;;;###autoload
|
||||
(define-minor-mode doom-popup-mode
|
||||
"Minor mode for popup windows."
|
||||
:init-value nil
|
||||
:keymap doom-popup-mode-map
|
||||
(let ((window (selected-window)))
|
||||
;; If `doom-popup-rules' isn't set for some reason, try to set it
|
||||
(setq-local doom-popup-rules (doom-popup-properties window))
|
||||
;; Ensure that buffer-opening functions/commands (like
|
||||
;; `switch-to-buffer-other-window' won't use this window).
|
||||
(set-window-parameter window 'no-other-window doom-popup-mode)
|
||||
;; Makes popup window resist interactively changing its buffer.
|
||||
(set-window-dedicated-p window doom-popup-mode)
|
||||
(cond (doom-popup-mode
|
||||
(when doom-popup-no-fringes
|
||||
(set-window-fringes window 0 0 fringes-outside-margins))
|
||||
;; Save metadata into window parameters so it can be saved by window
|
||||
;; config persisting plugins like workgroups or persp-mode.
|
||||
(set-window-parameter window 'popup (or doom-popup-rules t))
|
||||
(when doom-popup-rules
|
||||
(cl-loop for param in doom-popup-window-parameters
|
||||
when (plist-get doom-popup-rules param)
|
||||
do (set-window-parameter window param it))))
|
||||
|
||||
(t
|
||||
(when doom-popup-no-fringes
|
||||
(set-window-fringes window
|
||||
doom-fringe-size doom-fringe-size
|
||||
fringes-outside-margins))
|
||||
;; Ensure window parameters are cleaned up
|
||||
(set-window-parameter window 'popup nil)
|
||||
(dolist (param doom-popup-window-parameters)
|
||||
(set-window-parameter window param nil))))))
|
||||
(put 'doom-popup-mode 'permanent-local t)
|
||||
|
||||
;;;###autoload
|
||||
(defun doom|hide-modeline-in-popup ()
|
||||
"Don't show modeline in popup windows without a :modeline rule. If one exists
|
||||
and it's a symbol, use `doom-modeline' to grab the format. If non-nil, show the
|
||||
mode-line as normal. If nil (or omitted, by default), then hide the modeline
|
||||
entirely."
|
||||
(if doom-popup-mode
|
||||
(let ((modeline (plist-get doom-popup-rules :modeline)))
|
||||
(cond ((or (eq modeline 'nil)
|
||||
(not modeline))
|
||||
(doom-hide-modeline-mode +1))
|
||||
((and (symbolp modeline)
|
||||
(not (eq modeline 't)))
|
||||
(setq-local doom--modeline-format (doom-modeline modeline))
|
||||
(when doom--modeline-format
|
||||
(doom-hide-modeline-mode +1)))))
|
||||
(when doom-hide-modeline-mode
|
||||
(doom-hide-modeline-mode -1))))
|
||||
|
||||
|
||||
;; --- Advice functions -------------------
|
||||
|
||||
;;;###autoload
|
||||
(defun doom*shackle-always-align (plist)
|
||||
"Ensure popups are always aligned and selected by default. Eliminates the need
|
||||
for :align t on every rule."
|
||||
(when plist
|
||||
(unless (or (plist-member plist :align)
|
||||
(plist-member plist :same)
|
||||
(plist-member plist :frame))
|
||||
(plist-put plist :align t))
|
||||
(unless (or (plist-member plist :select)
|
||||
(plist-member plist :noselect))
|
||||
(plist-put plist :select t)))
|
||||
plist)
|
||||
|
||||
;;;###autoload
|
||||
(defun doom*popup-init (orig-fn &rest args)
|
||||
"Initializes a window as a popup window by enabling `doom-popup-mode' in it
|
||||
and setting `doom-popup-rules' within it. Returns the window."
|
||||
(unless (doom-popup-p)
|
||||
(setq doom-popup-other-window (selected-window)))
|
||||
(let* ((target (car args))
|
||||
(plist (or (nth 2 args)
|
||||
(cond ((windowp target)
|
||||
(and (window-live-p target)
|
||||
(shackle-match (window-buffer target))))
|
||||
((bufferp target)
|
||||
(and (buffer-live-p target)
|
||||
(shackle-match target))))))
|
||||
(buffer (get-buffer target))
|
||||
(window-min-height (if (plist-get plist :modeline) 4 2))
|
||||
window)
|
||||
(when (and (doom-real-buffer-p buffer)
|
||||
(get-buffer-window-list buffer nil t))
|
||||
(setq plist (append (list :autokill t) plist))
|
||||
(setcar args (clone-indirect-buffer (buffer-name target) nil t)))
|
||||
(unless (setq window (apply orig-fn args))
|
||||
(error "No popup window was found for %s: %s" target plist))
|
||||
(cl-pushnew window doom-popup-windows :test #'eq)
|
||||
(with-selected-window window
|
||||
(unless (eq plist t)
|
||||
(setq-local doom-popup-rules plist))
|
||||
(doom-popup-mode +1)
|
||||
(when (plist-get plist :autofit)
|
||||
(doom-popup-fit-to-buffer window)))
|
||||
window))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom*popups-save (orig-fn &rest args)
|
||||
"Sets aside all popups before executing the original function, usually to
|
||||
prevent the popup(s) from messing up the UI (or vice versa)."
|
||||
(save-popups! (apply orig-fn args)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom*delete-popup-window (&optional window)
|
||||
"Ensure that popups are deleted properly, and killed if they have :autokill
|
||||
properties."
|
||||
(or window (setq window (selected-window)))
|
||||
(when (doom-popup-p window)
|
||||
(setq doom-popup-windows (delq window doom-popup-windows))
|
||||
(when doom-popup-remember-history
|
||||
(setq doom-popup-history (list (doom--popup-data window))))
|
||||
(let ((autokill-p (and (not doom-popup-inhibit-autokill)
|
||||
(doom-popup-property :autokill window))))
|
||||
(with-selected-window window
|
||||
(doom-popup-mode -1)
|
||||
(when autokill-p
|
||||
(when-let (process (get-buffer-process (current-buffer)))
|
||||
(set-process-query-on-exit-flag process nil))
|
||||
(kill-buffer (current-buffer)))))))
|
||||
|
53
core/autoload/scratch.el
Normal file
53
core/autoload/scratch.el
Normal file
@ -0,0 +1,53 @@
|
||||
;;; core/autoload/scratch.el -*- lexical-binding: t; -*-
|
||||
|
||||
(defvar doom-scratch-files-dir (concat doom-etc-dir "scratch/")
|
||||
"Where to store project scratch files, created by
|
||||
`doom/open-project-scratch-buffer'.")
|
||||
|
||||
(defvar doom-scratch-buffer-hook ()
|
||||
"The hooks to run after a scratch buffer is made.")
|
||||
|
||||
(defun doom--create-scratch-buffer (&optional project-p)
|
||||
(let ((text (and (region-active-p)
|
||||
(buffer-substring-no-properties
|
||||
(region-beginning) (region-end))))
|
||||
(mode major-mode)
|
||||
(derived-p (derived-mode-p 'prog-mode 'text-mode))
|
||||
(old-project (doom-project-root)))
|
||||
(unless (file-directory-p doom-scratch-files-dir)
|
||||
(mkdir doom-scratch-files-dir t))
|
||||
(with-current-buffer
|
||||
(if project-p
|
||||
(find-file-noselect
|
||||
(expand-file-name (replace-regexp-in-string
|
||||
"\\." "_" (projectile-project-name)
|
||||
t t)
|
||||
doom-scratch-files-dir)
|
||||
nil t)
|
||||
(get-buffer-create "*doom:scratch*"))
|
||||
(when project-p
|
||||
(rename-buffer (format "*doom:scratch (%s)*" (projectile-project-name))))
|
||||
(setq default-directory old-project)
|
||||
(when (and (not (eq major-mode mode))
|
||||
derived-p
|
||||
(functionp mode))
|
||||
(funcall mode))
|
||||
(if text (insert text))
|
||||
(run-hooks 'doom-scratch-buffer-hook)
|
||||
(current-buffer))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/open-scratch-buffer ()
|
||||
"Opens a temporary scratch buffer in a popup window. It is discarded once it
|
||||
is closed. If a region is active, copy it to the scratch buffer."
|
||||
(interactive)
|
||||
(doom-popup-buffer (doom--create-scratch-buffer)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/open-project-scratch-buffer ()
|
||||
"Opens a (persistent) scratch buffer associated with the current project in a
|
||||
popup window. Scratch buffers are stored in `doom-scratch-files-dir'. If a
|
||||
region is active, copy it to the scratch buffer."
|
||||
(interactive)
|
||||
(doom-popup-buffer (doom--create-scratch-buffer t)))
|
||||
|
@ -1,19 +1,5 @@
|
||||
;;; core/autoload/test.el -*- lexical-binding: t; -*-
|
||||
|
||||
;;;###autoload
|
||||
(defmacro def-test! (name &rest body)
|
||||
"Define a namespaced ERT test."
|
||||
(declare (indent defun) (doc-string 2))
|
||||
(unless (plist-get body :disabled)
|
||||
`(ert-deftest
|
||||
,(cl-loop with path = (file-relative-name (file-name-sans-extension load-file-name)
|
||||
doom-emacs-dir)
|
||||
for (rep . with) in '(("/test/" . "/") ("/" . ":"))
|
||||
do (setq path (replace-regexp-in-string rep with path t t))
|
||||
finally return (intern (format "%s::%s" path name))) ()
|
||||
()
|
||||
,@body)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-run-tests (&optional modules)
|
||||
"Run all loaded tests, specified by MODULES (a list of module cons cells) or
|
||||
@ -83,3 +69,78 @@ If neither is available, run all tests in all enabled modules."
|
||||
(lwarn 'doom-test :error
|
||||
"%s -> %s"
|
||||
(car ex) (error-message-string ex)))))
|
||||
|
||||
|
||||
;; --- Test helpers -----------------------
|
||||
|
||||
(defmacro def-test! (name &rest body)
|
||||
"Define a namespaced ERT test."
|
||||
(declare (indent defun) (doc-string 2))
|
||||
(unless (plist-get body :disabled)
|
||||
`(ert-deftest
|
||||
,(cl-loop with path = (file-relative-name (file-name-sans-extension load-file-name)
|
||||
doom-emacs-dir)
|
||||
for (rep . with) in '(("/test/" . "/") ("/" . ":"))
|
||||
do (setq path (replace-regexp-in-string rep with path t t))
|
||||
finally return (intern (format "%s::%s" path name))) ()
|
||||
()
|
||||
,@body)))
|
||||
|
||||
(defmacro should-buffer! (initial expected &rest body)
|
||||
"Test that a buffer with INITIAL text, run BODY, then test it against EXPECTED.
|
||||
|
||||
INITIAL will recognize cursor markers in the form {[0-9]}. A {0} marker marks
|
||||
where the cursor should be after setup. Otherwise, the cursor will be placed at
|
||||
`point-min'.
|
||||
|
||||
EXPECTED will recognize one (optional) cursor marker: {|}, this is the
|
||||
'expected' location of the cursor after BODY is finished, and will be tested
|
||||
against."
|
||||
(declare (indent 2))
|
||||
`(with-temp-buffer
|
||||
(cl-loop for line in ',initial
|
||||
do (insert line "\n"))
|
||||
(goto-char (point-min))
|
||||
(let (marker-list)
|
||||
(save-excursion
|
||||
(while (re-search-forward "{\\([0-9]\\)}" nil t)
|
||||
(push (cons (match-string 1)
|
||||
(set-marker (make-marker) (match-beginning 0)))
|
||||
marker-list)
|
||||
(replace-match "" t t))
|
||||
(if (not marker-list)
|
||||
(goto-char (point-min))
|
||||
(sort marker-list
|
||||
(lambda (m1 m2) (< (marker-position m1)
|
||||
(marker-position m2))))
|
||||
(when (equal (caar marker-list) "0")
|
||||
(goto-char! 0)))
|
||||
,@body
|
||||
(let ((result-text (buffer-substring-no-properties (point-min) (point-max)))
|
||||
(point (point))
|
||||
same-point
|
||||
expected-text)
|
||||
(with-temp-buffer
|
||||
(cl-loop for line in ',expected
|
||||
do (insert line "\n"))
|
||||
(save-excursion
|
||||
(goto-char 1)
|
||||
(when (re-search-forward "{|}" nil t)
|
||||
(setq same-point (= point (match-beginning 0)))
|
||||
(replace-match "" t t)))
|
||||
(setq expected-text (buffer-substring-no-properties (point-min) (point-max)))
|
||||
(should (equal expected-text result-text))
|
||||
(should same-point)))))))
|
||||
|
||||
(defmacro goto-char! (index)
|
||||
"Meant to be used with `should-buffer!'. Will move the cursor to one of the
|
||||
cursor markers. e.g. Go to marker {2} with (goto-char! 2)."
|
||||
`(goto-char (point! ,index)))
|
||||
|
||||
(defmacro point! (index)
|
||||
"Meant to be used with `should-buffer!'. Returns the position of a cursor
|
||||
marker. e.g. {2} can be retrieved with (point! 2)."
|
||||
`(cdr (assoc ,(cond ((numberp index) (number-to-string index))
|
||||
((symbolp index) (symbol-name index))
|
||||
((stringp index) index))
|
||||
marker-list)))
|
||||
|
@ -26,10 +26,13 @@
|
||||
(error "No line number plugin detected"))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-resize-window (new-size &optional horizontal)
|
||||
"Resize a window to NEW-SIZE. If HORIZONTAL, do it width-wise."
|
||||
(defun doom-resize-window (window new-size &optional horizontal force-p)
|
||||
"Resize a window to NEW-SIZE. If HORIZONTAL, do it width-wise.
|
||||
If FORCE-P is omitted when `window-size-fixed' is non-nil, resizing will fail."
|
||||
(with-selected-window (or window (selected-window))
|
||||
(let ((window-size-fixed (unless force-p window-size-fixed)))
|
||||
(enlarge-window (- new-size (if horizontal (window-width) (window-height)))
|
||||
horizontal))
|
||||
horizontal))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/window-zoom ()
|
||||
@ -52,8 +55,8 @@ window changes before then, the undo expires."
|
||||
(assoc ?_ register-alist))
|
||||
(ignore (jump-to-register ?_))
|
||||
(window-configuration-to-register ?_)
|
||||
(doom-resize-window (truncate (/ (frame-width) 1.2)) t)
|
||||
(doom-resize-window (truncate (/ (frame-height) 1.2)))
|
||||
(doom-resize-window nil (truncate (/ (frame-width) 1.2)) t)
|
||||
(doom-resize-window nil (truncate (/ (frame-height) 1.2)))
|
||||
t)))
|
||||
|
||||
;;;###autoload
|
||||
|
@ -155,7 +155,6 @@ with functions that require it (like modeline segments)."
|
||||
(setq recentf-save-file (concat doom-cache-dir "recentf")
|
||||
recentf-max-menu-items 0
|
||||
recentf-max-saved-items 300
|
||||
recentf-filename-handlers '(abbreviate-file-name)
|
||||
recentf-exclude
|
||||
(list "^/tmp/" "^/ssh:" "\\.?ido\\.last$" "\\.revive$" "/TAGS$"
|
||||
"^/var/folders/.+$"
|
||||
@ -173,7 +172,6 @@ with functions that require it (like modeline segments)."
|
||||
;; specify their own formatting rules.
|
||||
(def-package! editorconfig
|
||||
:demand t
|
||||
:mode ("\\.?editorconfig$" . editorconfig-conf-mode)
|
||||
:init
|
||||
(def-setting! :editorconfig (action value)
|
||||
":add or :remove an entry in `editorconfig-indentation-alist'."
|
||||
@ -201,6 +199,9 @@ with functions that require it (like modeline segments)."
|
||||
(whitespace-mode +1))))
|
||||
(add-hook 'editorconfig-custom-hooks #'doom|editorconfig-whitespace-mode-maybe))
|
||||
|
||||
(def-package! editorconfig-conf-mode
|
||||
:mode "\\.?editorconfig$")
|
||||
|
||||
;; Auto-close delimiters and blocks as you type
|
||||
(def-package! smartparens
|
||||
:demand t
|
||||
@ -269,11 +270,6 @@ with functions that require it (like modeline segments)."
|
||||
:commands (describe-buffer describe-command describe-file
|
||||
describe-keymap describe-option describe-option-of-type))
|
||||
|
||||
(def-package! imenu-anywhere
|
||||
:commands (ido-imenu-anywhere ivy-imenu-anywhere helm-imenu-anywhere))
|
||||
|
||||
(def-package! imenu-list :commands imenu-list-minor-mode)
|
||||
|
||||
(def-package! pcre2el :commands rxt-quote-pcre)
|
||||
|
||||
(def-package! smart-forward
|
||||
|
@ -36,6 +36,60 @@
|
||||
(add-hook 'doom-init-hook #'which-key-mode))
|
||||
|
||||
|
||||
(def-package! hydra
|
||||
:demand t
|
||||
:init
|
||||
;; In case I later need to wrap defhydra in any special functionality.
|
||||
(defalias 'def-hydra! 'defhydra)
|
||||
(defalias 'def-hydra-radio! 'defhydradio)
|
||||
:config
|
||||
(setq lv-use-seperator t)
|
||||
|
||||
(def-hydra! doom@text-zoom (:hint t :color red)
|
||||
"
|
||||
Text zoom: _j_:zoom in, _k_:zoom out, _0_:reset
|
||||
"
|
||||
("j" text-scale-increase "in")
|
||||
("k" text-scale-decrease "out")
|
||||
("0" (text-scale-set 0) "reset"))
|
||||
|
||||
(def-hydra! doom@window-nav (:hint nil)
|
||||
"
|
||||
Split: _v_ert _s_:horz
|
||||
Delete: _c_lose _o_nly
|
||||
Switch Window: _h_:left _j_:down _k_:up _l_:right
|
||||
Buffers: _p_revious _n_ext _b_:select _f_ind-file
|
||||
Resize: _H_:splitter left _J_:splitter down _K_:splitter up _L_:splitter right
|
||||
Move: _a_:up _z_:down _i_menu
|
||||
"
|
||||
("z" scroll-up-line)
|
||||
("a" scroll-down-line)
|
||||
("i" idomenu)
|
||||
|
||||
("h" windmove-left)
|
||||
("j" windmove-down)
|
||||
("k" windmove-up)
|
||||
("l" windmove-right)
|
||||
|
||||
("p" doom/previous-buffer)
|
||||
("n" doom/next-buffer)
|
||||
("b" switch-to-buffer)
|
||||
("f" find-file)
|
||||
|
||||
("s" split-window-below)
|
||||
("v" split-window-right)
|
||||
|
||||
("c" delete-window)
|
||||
("o" delete-other-windows)
|
||||
|
||||
("H" hydra-move-splitter-left)
|
||||
("J" hydra-move-splitter-down)
|
||||
("K" hydra-move-splitter-up)
|
||||
("L" hydra-move-splitter-right)
|
||||
|
||||
("q" nil)))
|
||||
|
||||
|
||||
;;
|
||||
(defun doom--keybind-register (key desc &optional modes)
|
||||
"Register a description for KEY with `which-key' in MODES.
|
||||
|
@ -29,7 +29,7 @@
|
||||
;; Helpers
|
||||
;;
|
||||
|
||||
(defun doom--resolve-paths (paths &optional root)
|
||||
(defun doom--resolve-path-forms (paths &optional root)
|
||||
(cond ((stringp paths)
|
||||
`(file-exists-p
|
||||
(expand-file-name
|
||||
@ -39,10 +39,10 @@
|
||||
(or root `(doom-project-root))))))
|
||||
((listp paths)
|
||||
(cl-loop for i in paths
|
||||
collect (doom--resolve-paths i root)))
|
||||
collect (doom--resolve-path-forms i root)))
|
||||
(t paths)))
|
||||
|
||||
(defun doom--resolve-hooks (hooks)
|
||||
(defun doom--resolve-hook-forms (hooks)
|
||||
(cl-loop with quoted-p = (eq (car-safe hooks) 'quote)
|
||||
for hook in (doom-enlist (doom-unquote hooks))
|
||||
if (eq (car-safe hook) 'quote)
|
||||
@ -61,6 +61,81 @@
|
||||
"Return EXP wrapped in a list, or as-is if already a list."
|
||||
(if (listp exp) exp (list exp)))
|
||||
|
||||
(defun doom-resolve-vim-path (file-name)
|
||||
"Take a path and resolve any vim-like filename modifiers in it. This adds
|
||||
support for these special modifiers:
|
||||
|
||||
%:P Resolves to `doom-project-root'.
|
||||
|
||||
See http://vimdoc.sourceforge.net/htmldoc/cmdline.html#filename-modifiers."
|
||||
(let* (case-fold-search
|
||||
(regexp (concat "\\(?:^\\|[^\\\\]\\)"
|
||||
"\\([#%]\\)"
|
||||
"\\(\\(?::\\(?:[PphtreS~.]\\|g?s[^:\t\n ]+\\)\\)*\\)"))
|
||||
(matches
|
||||
(cl-loop with i = 0
|
||||
while (and (< i (length file-name))
|
||||
(string-match regexp file-name i))
|
||||
do (setq i (1+ (match-beginning 0)))
|
||||
and collect
|
||||
(cl-loop for j to (/ (length (match-data)) 2)
|
||||
collect (match-string j file-name)))))
|
||||
(dolist (match matches)
|
||||
(let ((flags (split-string (car (cdr (cdr match))) ":" t))
|
||||
(path (and buffer-file-name
|
||||
(pcase (car (cdr match))
|
||||
("%" (file-relative-name buffer-file-name))
|
||||
("#" (save-excursion (other-window 1) (file-relative-name buffer-file-name))))))
|
||||
flag global)
|
||||
(if (not path)
|
||||
(setq path "")
|
||||
(while flags
|
||||
(setq flag (pop flags))
|
||||
(when (string-suffix-p "\\" flag)
|
||||
(setq flag (concat flag (pop flags))))
|
||||
(when (string-prefix-p "gs" flag)
|
||||
(setq global t
|
||||
flag (substring flag 1)))
|
||||
(setq path
|
||||
(or (pcase (substring flag 0 1)
|
||||
("p" (expand-file-name path))
|
||||
("~" (concat "~/" (file-relative-name path "~")))
|
||||
("." (file-relative-name path default-directory))
|
||||
("t" (file-name-nondirectory (directory-file-name path)))
|
||||
("r" (file-name-sans-extension path))
|
||||
("e" (file-name-extension path))
|
||||
("S" (shell-quote-argument path))
|
||||
("h"
|
||||
(let ((parent (file-name-directory (expand-file-name path))))
|
||||
(unless (equal (file-truename path)
|
||||
(file-truename parent))
|
||||
(if (file-name-absolute-p path)
|
||||
(directory-file-name parent)
|
||||
(file-relative-name parent)))))
|
||||
("s"
|
||||
(if (featurep 'evil)
|
||||
(when-let (args (evil-delimited-arguments (substring flag 1) 2))
|
||||
(let ((pattern (evil-transform-vim-style-regexp (car args)))
|
||||
(replace (cadr args)))
|
||||
(replace-regexp-in-string
|
||||
(if global pattern (concat "\\(" pattern "\\).*\\'"))
|
||||
(evil-transform-vim-style-regexp replace) path t t
|
||||
(unless global 1))))
|
||||
path))
|
||||
("P"
|
||||
(let ((default-directory (file-name-directory (expand-file-name path))))
|
||||
(abbreviate-file-name (doom-project-root))))
|
||||
(_ path))
|
||||
"")))
|
||||
;; strip trailing slash, if applicable
|
||||
(when (and (not (string= path "")) (equal (substring path -1) "/"))
|
||||
(setq path (substring path 0 -1))))
|
||||
(setq file-name
|
||||
(replace-regexp-in-string (format "\\(?:^\\|[^\\\\]\\)\\(%s\\)"
|
||||
(regexp-quote (string-trim-left (car match))))
|
||||
path file-name t t 1))))
|
||||
(replace-regexp-in-string regexp "\\1" file-name t)))
|
||||
|
||||
|
||||
;;
|
||||
;; Library
|
||||
@ -153,7 +228,7 @@ Body forms can access the hook's arguments through the let-bound variable
|
||||
(:append (setq append-p t))
|
||||
(:local (setq local-p t))
|
||||
(:remove (setq hook-fn 'remove-hook))))
|
||||
(let ((hooks (doom--resolve-hooks (pop args)))
|
||||
(let ((hooks (doom--resolve-hook-forms (pop args)))
|
||||
(funcs
|
||||
(let ((val (car args)))
|
||||
(if (memq (car-safe val) '(quote function))
|
||||
@ -199,11 +274,11 @@ Body forms can access the hook's arguments through the let-bound variable
|
||||
(not ,mode)
|
||||
(and buffer-file-name (not (file-remote-p buffer-file-name)))
|
||||
,(if match `(if buffer-file-name (string-match-p ,match buffer-file-name)) t)
|
||||
,(if files (doom--resolve-paths files) t)
|
||||
,(if files (doom--resolve-path-forms files) t)
|
||||
,(or pred-form t))
|
||||
(,mode 1)))
|
||||
,@(if (and modes (listp modes))
|
||||
(cl-loop for hook in (doom--resolve-hooks modes)
|
||||
(cl-loop for hook in (doom--resolve-hook-forms modes)
|
||||
collect `(add-hook ',hook ',hook-name))
|
||||
`((add-hook 'after-change-major-mode-hook ',hook-name))))))
|
||||
(match
|
||||
@ -213,11 +288,10 @@ Body forms can access the hook's arguments through the let-bound variable
|
||||
|
||||
|
||||
;; I'm a fan of concise, hassle-free front-facing configuration. Rather than
|
||||
;; littering my config with `after!' blocks, these two macros offer a faster and
|
||||
;; more robust alternative. The motivation: to facilitate concise cross-module
|
||||
;; configuration.
|
||||
;;
|
||||
;; It also benefits from byte-compilation.
|
||||
;; littering my config with `after!' blocks, and checking if features and
|
||||
;; modules are loaded before every line of config, I wrote `set!' as a more
|
||||
;; robust alternative. If a setting doesn't exist at run-time, the `set!' call
|
||||
;; is ignored. It also benefits from byte-compilation.
|
||||
(defvar doom-settings nil)
|
||||
|
||||
(defmacro def-setting! (keyword arglist &optional docstring &rest forms)
|
||||
|
@ -76,7 +76,7 @@ missing) and shouldn't be deleted.")
|
||||
"A list of packages that should be ignored by `def-package!'.")
|
||||
|
||||
(defvar doom-reload-hook nil
|
||||
"A list of hooks to run when `doom/reload' is called.")
|
||||
"A list of hooks to run when `doom/reload-load-path' is called.")
|
||||
|
||||
(defvar doom--site-load-path load-path
|
||||
"The load path of built in Emacs libraries.")
|
||||
@ -90,7 +90,6 @@ missing) and shouldn't be deleted.")
|
||||
"A backup of `load-path' before it was altered by `doom-initialize'. Used as a
|
||||
base by `doom!' and for calculating how many packages exist.")
|
||||
|
||||
(defvar doom--module nil)
|
||||
(defvar doom--refresh-p nil)
|
||||
|
||||
(setq load-prefer-newer (or noninteractive doom-debug-mode)
|
||||
@ -136,33 +135,27 @@ base by `doom!' and for calculating how many packages exist.")
|
||||
|
||||
(defun doom-initialize (&optional force-p)
|
||||
"Initialize installed packages (using package.el) and ensure the core packages
|
||||
are installed. If you byte-compile core/core.el, this function will be avoided
|
||||
to speed up startup."
|
||||
are installed.
|
||||
|
||||
If you byte-compile core/core.el, this function will be avoided to speed up
|
||||
startup."
|
||||
;; Called early during initialization; only use native functions!
|
||||
(when (or (not doom-package-init-p) force-p)
|
||||
(unless noninteractive
|
||||
(message "Doom initialized"))
|
||||
|
||||
(setq load-path doom--base-load-path
|
||||
package-activated-list nil)
|
||||
|
||||
;; Ensure core folders exist
|
||||
(dolist (dir (list doom-local-dir doom-etc-dir doom-cache-dir package-user-dir))
|
||||
(unless (file-directory-p dir)
|
||||
(make-directory dir t)))
|
||||
|
||||
(package-initialize t)
|
||||
;; Sure, we could let `package-initialize' fill `load-path', but package
|
||||
;; activation costs precious milliseconds and does other stuff I don't
|
||||
;; really care about (like load autoload files). My premature optimization
|
||||
;; quota isn't filled yet.
|
||||
;; We could let `package-initialize' fill `load-path', but it costs precious
|
||||
;; milliseconds and does other stuff I don't need (like load autoload
|
||||
;; files). My premature optimization quota isn't filled yet.
|
||||
;;
|
||||
;; Also, in some edge cases involving package initialization during a
|
||||
;; non-interactive session, `package-initialize' fails to fill `load-path'.
|
||||
;; If we want something done right, do it ourselves!
|
||||
(setq doom--package-load-path (directory-files package-user-dir t "^[^.]" t)
|
||||
load-path (append load-path doom--package-load-path))
|
||||
|
||||
;; Ensure core packages are installed
|
||||
(dolist (pkg doom-core-packages)
|
||||
(unless (package-installed-p pkg)
|
||||
@ -174,11 +167,11 @@ to speed up startup."
|
||||
(if (package-installed-p pkg)
|
||||
(message "Installed %s" pkg)
|
||||
(error "Couldn't install %s" pkg))))
|
||||
|
||||
(load "quelpa" nil t)
|
||||
(load "use-package" nil t)
|
||||
|
||||
(setq doom-package-init-p t)))
|
||||
(setq doom-package-init-p t)
|
||||
(unless noninteractive
|
||||
(message "Doom initialized"))))
|
||||
|
||||
(defun doom-initialize-autoloads ()
|
||||
"Ensures that `doom-autoload-file' exists and is loaded. Otherwise run
|
||||
@ -195,6 +188,7 @@ If FORCE-P is non-nil, do it even if they are.
|
||||
This aggressively reloads core autoload files."
|
||||
(doom-initialize force-p)
|
||||
(let ((noninteractive t)
|
||||
(load-prefer-newer t)
|
||||
(load-fn
|
||||
(lambda (file &optional noerror)
|
||||
(condition-case-unless-debug ex
|
||||
@ -219,9 +213,7 @@ This aggressively reloads core autoload files."
|
||||
(funcall load-fn (expand-file-name "packages.el" doom-core-dir))
|
||||
(cl-loop for (module . submodule) in (doom--module-pairs)
|
||||
for path = (doom-module-path module submodule "packages.el")
|
||||
do
|
||||
(let ((doom--module (cons module submodule)))
|
||||
(funcall load-fn path t))))))
|
||||
do (funcall load-fn path t)))))
|
||||
|
||||
(defun doom-initialize-modules (modules)
|
||||
"Adds MODULES to `doom-modules'. MODULES must be in mplist format.
|
||||
@ -233,14 +225,10 @@ This aggressively reloads core autoload files."
|
||||
:rehash-threshold 1.0)))
|
||||
(let (mode)
|
||||
(dolist (m modules)
|
||||
(cond ((keywordp m)
|
||||
(setq mode m))
|
||||
((not mode)
|
||||
(error "No namespace specified on `doom!' for %s" m))
|
||||
((listp m)
|
||||
(doom-module-enable mode (car m) (cdr m)))
|
||||
(t
|
||||
(doom-module-enable mode m))))))
|
||||
(cond ((keywordp m) (setq mode m))
|
||||
((not mode) (error "No namespace specified on `doom!' for %s" m))
|
||||
((listp m) (doom-module-enable mode (car m) (cdr m)))
|
||||
(t (doom-module-enable mode m))))))
|
||||
|
||||
(defun doom-module-path (module submodule &optional file)
|
||||
"Get the full path to a module: e.g. :lang emacs-lisp maps to
|
||||
@ -252,6 +240,12 @@ This aggressively reloads core autoload files."
|
||||
(expand-file-name (concat module "/" submodule "/" file)
|
||||
doom-modules-dir))
|
||||
|
||||
(defun doom-module-from-path (path)
|
||||
"Get module cons cell (MODULE . SUBMODULE) for PATH, if possible."
|
||||
(when (string-match (concat doom-modules-dir "\\([^/]+\\)/\\([^/]+\\)/") path)
|
||||
(cons (intern (concat ":" (match-string 1 path)))
|
||||
(intern (match-string 2 path)))))
|
||||
|
||||
(defun doom-module-flags (module submodule)
|
||||
"Returns a list of flags provided for MODULE SUBMODULE."
|
||||
(and (hash-table-p doom-modules)
|
||||
@ -288,14 +282,13 @@ added, if the file exists."
|
||||
if (file-exists-p path)
|
||||
collect path))
|
||||
|
||||
|
||||
|
||||
(defun doom--display-benchmark ()
|
||||
(message "Loaded %s packages in %.03fs"
|
||||
(message "Doom loaded %s packages across %d modules in %.03fs"
|
||||
;; Certainly imprecise, especially where custom additions to
|
||||
;; load-path are concerned, but I don't mind a [small] margin of
|
||||
;; error in the plugin count in exchange for faster startup.
|
||||
(- (length load-path) (length doom--base-load-path))
|
||||
(hash-table-size doom-modules)
|
||||
(setq doom-init-time (float-time (time-subtract after-init-time before-init-time)))))
|
||||
|
||||
|
||||
@ -326,7 +319,8 @@ MODULES is an malformed plist of modules to load."
|
||||
(unless (server-running-p)
|
||||
(server-start)))
|
||||
|
||||
(add-hook 'doom-init-hook #'doom--display-benchmark t))))
|
||||
(add-hook 'doom-init-hook #'doom--display-benchmark t)
|
||||
(message "Doom modules initialized"))))
|
||||
|
||||
(defmacro def-package! (name &rest plist)
|
||||
"A thin wrapper around `use-package'.
|
||||
@ -406,8 +400,7 @@ The module is only loaded once. If RELOAD-P is non-nil, load it again."
|
||||
(unless loaded-p
|
||||
(doom-module-enable module submodule flags))
|
||||
`(condition-case-unless-debug ex
|
||||
(let ((doom--module ',(cons module submodule)))
|
||||
(load! config ,(doom-module-path module submodule) t))
|
||||
(load! config ,(doom-module-path module submodule) t)
|
||||
('error
|
||||
(lwarn 'doom-modules :error
|
||||
"%s in '%s %s' -> %s"
|
||||
@ -418,11 +411,13 @@ The module is only loaded once. If RELOAD-P is non-nil, load it again."
|
||||
"A convenience macro wrapper for `doom-module-loaded-p'. It is evaluated at
|
||||
compile-time/macro-expansion time."
|
||||
(unless submodule
|
||||
(unless doom--module
|
||||
(error "featurep! was used incorrectly (doom--module wasn't unset)"))
|
||||
(let* ((path (or load-file-name byte-compile-current-file))
|
||||
(module-pair (doom-module-from-path path)))
|
||||
(unless module-pair
|
||||
(error "featurep! couldn't detect what module I'm in! (in %s)" path))
|
||||
(setq flag module
|
||||
module (car doom--module)
|
||||
submodule (cdr doom--module)))
|
||||
module (car module-pair)
|
||||
submodule (cdr module-pair))))
|
||||
(if flag
|
||||
(and (memq flag (doom-module-flags module submodule)) t)
|
||||
(doom-module-loaded-p module submodule)))
|
||||
@ -487,7 +482,7 @@ loads MODULE SUBMODULE's packages.el file."
|
||||
;; Commands
|
||||
;;
|
||||
|
||||
(defun doom/reload ()
|
||||
(defun doom/reload-load-path ()
|
||||
"Reload `load-path' and recompile files (if necessary).
|
||||
|
||||
Use this when `load-path' is out of sync with your plugins. This should only
|
||||
@ -495,12 +490,12 @@ happen if you manually modify/update/install packages from outside Emacs, while
|
||||
an Emacs session is running.
|
||||
|
||||
This isn't necessary if you use Doom's package management commands because they
|
||||
call `doom/reload' remotely (through emacsclient)."
|
||||
call `doom/reload-load-path' remotely (through emacsclient)."
|
||||
(interactive)
|
||||
(cond (noninteractive
|
||||
(message "Reloading...")
|
||||
(require 'server)
|
||||
(unless (ignore-errors (server-eval-at "server" '(doom/reload)))
|
||||
(unless (ignore-errors (server-eval-at "server" '(doom/reload-load-path)))
|
||||
(message "Recompiling")
|
||||
(doom/recompile)))
|
||||
(t
|
||||
@ -626,6 +621,7 @@ If ONLY-RECOMPILE-P is non-nil, only recompile out-of-date files."
|
||||
total-fail)
|
||||
(t
|
||||
(message! (green "Compiled %s" short-name))
|
||||
(quiet! (load file t t))
|
||||
total-success))))))
|
||||
(message!
|
||||
(bold
|
||||
|
@ -18,10 +18,6 @@
|
||||
"A list of popups that were last closed. Used by `doom/popup-restore' and
|
||||
`doom*popups-save'.")
|
||||
|
||||
(defvar doom-popup-remember-history t
|
||||
"If non-nil, DOOM will remember the last popup(s) that were open in
|
||||
`doom-popup-history'.")
|
||||
|
||||
(defvar doom-popup-other-window nil
|
||||
"The last window selected before a popup was opened.")
|
||||
|
||||
@ -32,33 +28,53 @@
|
||||
"A list of open popup windows.")
|
||||
|
||||
(defvar-local doom-popup-rules nil
|
||||
"The shackle rule that caused this buffer to be recognized as a popup.")
|
||||
"The shackle rule that caused this buffer to be recognized as a popup. Don't
|
||||
edit this directly.")
|
||||
(put 'doom-popup-rules 'permanent-local t)
|
||||
|
||||
(defvar doom-popup-window-parameters
|
||||
'(:noesc :modeline :autokill :autoclose)
|
||||
'(:noesc :modeline :autokill :autoclose :autofit :static)
|
||||
"A list of window parameters that are set (and cleared) when `doom-popup-mode
|
||||
is enabled/disabled.'")
|
||||
|
||||
(defvar doom-popup-remember-history t
|
||||
"Don't modify this directly. If non-nil, DOOM will remember the last popup(s)
|
||||
that was/were open in `doom-popup-history'.")
|
||||
|
||||
(defvar doom-popup-inhibit-autokill nil
|
||||
"Don't modify this directly. When it is non-nil, no buffers will be killed
|
||||
when their associated popup windows are closed, despite their :autokill
|
||||
property.")
|
||||
|
||||
|
||||
(def-setting! :popup (&rest rules)
|
||||
"Prepend a new popup rule to `shackle-rules' (see for format details).
|
||||
|
||||
Several custom properties have been added that are not part of shackle, but are
|
||||
recognized by DOOM's popup system. They are:
|
||||
|
||||
:noesc If non-nil, pressing ESC *inside* the popup will close it.
|
||||
Used by `doom/popup-close-maybe'.
|
||||
:noesc If non-nil, the popup won't be closed if you press ESC from *inside*
|
||||
its window. Used by `doom/popup-close-maybe'.
|
||||
|
||||
:modeline By default, mode-lines are hidden in popups unless this
|
||||
is non-nil. If it is a symbol, it'll use `doom-modeline'
|
||||
to fetch a modeline config (in `doom-popup-mode').
|
||||
:modeline By default, mode-lines are hidden in popups unless this is non-nil.
|
||||
If it is a symbol, it'll use `doom-modeline' to fetch a modeline
|
||||
config (in `doom-popup-mode').
|
||||
|
||||
:autokill If non-nil, the popup's buffer will be killed when the
|
||||
popup is closed. Used by `doom*delete-popup-window'.
|
||||
NOTE `doom/popup-restore' can't restore non-file popups
|
||||
that have an :autokill property.
|
||||
:autokill If non-nil, the popup's buffer will be killed when the popup is
|
||||
closed. Used by `doom*delete-popup-window'. NOTE
|
||||
`doom/popup-restore' can't restore non-file popups that have an
|
||||
:autokill property.
|
||||
|
||||
:autoclose If non-nil, close popup if ESC is pressed from outside
|
||||
the popup window."
|
||||
:autoclose If non-nil, close popup if ESC is pressed from outside the popup
|
||||
window.
|
||||
|
||||
:autofit If non-nil, resize the popup to fit its content. Uses the value of
|
||||
the :size property as the maximum height/width. This will not work
|
||||
if the popup has no content when displayed.
|
||||
|
||||
:static If non-nil, don't treat this window like a popup. This makes it
|
||||
impervious to being automatically closed or tracked in popup
|
||||
history. Excellent for permanent sidebars."
|
||||
(if (cl-every #'listp (mapcar #'doom-unquote rules))
|
||||
`(setq shackle-rules (nconc (list ,@rules) shackle-rules))
|
||||
`(push (list ,@rules) shackle-rules)))
|
||||
@ -74,17 +90,19 @@ recognized by DOOM's popup system. They are:
|
||||
(setq shackle-default-alignment 'below
|
||||
shackle-default-size 8
|
||||
shackle-rules
|
||||
'(("^\\*ftp " :noselect t :autokill t :noesc t)
|
||||
'(("^\\*eww" :regexp t :size 0.5 :select t :autokill t :noesc t)
|
||||
("^\\*ftp " :noselect t :autokill t :noesc t)
|
||||
;; doom
|
||||
("^\\*doom:" :regexp t :size 0.35 :noesc t :select t :modeline t)
|
||||
("^\\*doom " :regexp t :noselect t :autokill t :autoclose t)
|
||||
("^\\*doom:scratch" :regexp t :size 15 :noesc t :select t :modeline t :autokill t :static t)
|
||||
("^\\*doom:" :regexp t :size 0.35 :noesc t :select t)
|
||||
("^ ?\\*doom " :regexp t :noselect t :autokill t :autoclose t :autofit t)
|
||||
;; built-in (emacs)
|
||||
("*ert*" :same t :modeline t)
|
||||
("*info*" :size 0.5 :select t :autokill t)
|
||||
("*Backtrace*" :size 20 :noselect t)
|
||||
("*Warnings*" :size 8 :noselect t)
|
||||
("*Warnings*" :size 12 :noselect t :autofit t)
|
||||
("*Messages*" :size 12 :noselect t)
|
||||
("*Help*" :size 0.3)
|
||||
("*Help*" :size 0.4 :autofit t)
|
||||
("^\\*.*Shell Command.*\\*$" :regexp t :size 20 :noselect t :autokill t)
|
||||
(apropos-mode :size 0.3 :autokill t :autoclose t)
|
||||
(Buffer-menu-mode :size 20 :autokill t)
|
||||
@ -92,171 +110,43 @@ recognized by DOOM's popup system. They are:
|
||||
(grep-mode :size 25 :noselect t :autokill t)
|
||||
(profiler-report-mode :size 0.3 :regexp t :autokill t :modeline minimal)
|
||||
(tabulated-list-mode :noesc t)
|
||||
(special-mode :noselect t :autokill t :autoclose t)
|
||||
("^\\*" :regexp t :noselect t :autokill t)
|
||||
("^ \\*" :regexp t :size 12 :noselect t :autokill t :autoclose t)))
|
||||
("^ ?\\*" :regexp t :size 0.3 :noselect t :autokill t :autoclose t :autofit t)))
|
||||
|
||||
:config
|
||||
(add-hook 'doom-post-init-hook #'shackle-mode)
|
||||
|
||||
(defun doom*shackle-always-align (plist)
|
||||
"Ensure popups are always aligned and selected by default. Eliminates the need
|
||||
for :align t on every rule."
|
||||
(when plist
|
||||
(unless (or (plist-member plist :align)
|
||||
(plist-member plist :same)
|
||||
(plist-member plist :frame))
|
||||
(plist-put plist :align t))
|
||||
(unless (or (plist-member plist :select)
|
||||
(plist-member plist :noselect))
|
||||
(plist-put plist :select t)))
|
||||
plist)
|
||||
(advice-add #'shackle--match :filter-return #'doom*shackle-always-align))
|
||||
;; no modeline in popups
|
||||
(add-hook 'doom-popup-mode-hook #'doom|hide-modeline-in-popup)
|
||||
;; ensure every rule without an :align, :same or :frame property has an
|
||||
;; implicit :align (see `shackle-default-alignment')
|
||||
(advice-add #'shackle--match :filter-return #'doom*shackle-always-align)
|
||||
|
||||
;; bootstrap popup system
|
||||
(advice-add #'shackle-display-buffer :around #'doom*popup-init)
|
||||
(advice-add #'balance-windows :around #'doom*popups-save)
|
||||
(advice-add #'delete-window :before #'doom*delete-popup-window)
|
||||
|
||||
;;
|
||||
;; Integration
|
||||
;;
|
||||
|
||||
;; Tell `window-state-get' and `current-window-configuration' to recognize these
|
||||
;; custom parameters. Helpful for `persp-mode' and persisting window configs
|
||||
;; that have popups in them.
|
||||
(dolist (param (cons 'popup doom-popup-window-parameters))
|
||||
;; Tell `window-state-get' and `current-window-configuration' to recognize
|
||||
;; these custom parameters. Helpful for `persp-mode' and persisting window
|
||||
;; configs that have popups in them.
|
||||
(dolist (param `(popup ,@doom-popup-window-parameters))
|
||||
(push (cons param 'writable) window-persistent-parameters))
|
||||
|
||||
(defvar doom-popup-mode-map
|
||||
(let ((map (make-sparse-keymap)))
|
||||
(define-key map [escape] 'doom/popup-close-maybe)
|
||||
(define-key map (kbd "ESC") 'doom/popup-close-maybe)
|
||||
(define-key map [remap doom-kill-buffer] 'kill-this-buffer)
|
||||
(define-key map [remap doom/kill-this-buffer] 'kill-this-buffer)
|
||||
(define-key map [remap split-window-right] 'ignore)
|
||||
(define-key map [remap split-window-below] 'ignore)
|
||||
(define-key map [remap split-window-horizontally] 'ignore)
|
||||
(define-key map [remap split-window-vertically] 'ignore)
|
||||
(define-key map [remap mouse-split-window-horizontally] 'ignore)
|
||||
(define-key map [remap mouse-split-window-vertically] 'ignore)
|
||||
(define-key map [escape] #'doom/popup-close-maybe)
|
||||
(define-key map (kbd "ESC") #'doom/popup-close-maybe)
|
||||
(define-key map [remap quit-window] #'doom/popup-close-maybe)
|
||||
(define-key map [remap delete-window] #'doom/popup-close-maybe)
|
||||
(define-key map [remap doom/kill-this-buffer] #'delete-window)
|
||||
(define-key map [remap split-window-right] #'ignore)
|
||||
(define-key map [remap split-window-below] #'ignore)
|
||||
(define-key map [remap split-window-horizontally] #'ignore)
|
||||
(define-key map [remap split-window-vertically] #'ignore)
|
||||
(define-key map [remap mouse-split-window-horizontally] #'ignore)
|
||||
(define-key map [remap mouse-split-window-vertically] #'ignore)
|
||||
map)
|
||||
"Active keymap in popup windows.")
|
||||
|
||||
(define-minor-mode doom-popup-mode
|
||||
"Minor mode for popup windows."
|
||||
:init-value nil
|
||||
:keymap doom-popup-mode-map
|
||||
(let ((window (selected-window)))
|
||||
;; If `doom-popup-rules' isn't set for some reason, try to set it
|
||||
(when-let (plist (and (not doom-popup-rules)
|
||||
(window-parameter window 'popup)))
|
||||
(setq-local doom-popup-rules (window-parameter window 'popup)))
|
||||
;; Ensure that buffer-opening functions/commands (like
|
||||
;; `switch-to-buffer-other-window' won't use this window).
|
||||
(set-window-parameter window 'no-other-window doom-popup-mode)
|
||||
;; Makes popup window resist interactively changing its buffer.
|
||||
(set-window-dedicated-p window doom-popup-mode)
|
||||
(cond (doom-popup-mode
|
||||
(when doom-popup-no-fringes
|
||||
(set-window-fringes window 0 0 fringes-outside-margins))
|
||||
;; Save metadata into window parameters so it can be saved by window
|
||||
;; config persisting plugins like workgroups or persp-mode.
|
||||
(set-window-parameter window 'popup (or doom-popup-rules t))
|
||||
(when doom-popup-rules
|
||||
(cl-loop for param in doom-popup-window-parameters
|
||||
when (plist-get doom-popup-rules param)
|
||||
do (set-window-parameter window param it))))
|
||||
|
||||
(t
|
||||
(when doom-popup-no-fringes
|
||||
(set-window-fringes window
|
||||
doom-fringe-size doom-fringe-size
|
||||
fringes-outside-margins))
|
||||
;; Ensure window parameters are cleaned up
|
||||
(set-window-parameter window 'popup nil)
|
||||
(dolist (param doom-popup-window-parameters)
|
||||
(set-window-parameter window param nil))))))
|
||||
|
||||
;; Major mode changes (and other things) may call `kill-all-local-variables',
|
||||
;; turning off things like `doom-popup-mode'. This prevents that.
|
||||
(put 'doom-popup-mode 'permanent-local t)
|
||||
(put 'doom-popup-rules 'permanent-local t)
|
||||
|
||||
(defun doom|hide-modeline-in-popup ()
|
||||
"Don't show modeline in popup windows without a :modeline rule. If one exists
|
||||
and it's a symbol, use `doom-modeline' to grab the format. If non-nil, show the
|
||||
mode-line as normal. If nil (or omitted, by default), then hide the modeline
|
||||
entirely."
|
||||
(if doom-popup-mode
|
||||
(let ((modeline (plist-get doom-popup-rules :modeline)))
|
||||
(cond ((or (eq modeline 'nil)
|
||||
(not modeline))
|
||||
(doom-hide-modeline-mode +1))
|
||||
((and (symbolp modeline)
|
||||
(not (eq modeline 't)))
|
||||
(setq-local doom--modeline-format (doom-modeline modeline))
|
||||
(when doom--modeline-format
|
||||
(doom-hide-modeline-mode +1)))))
|
||||
(when doom-hide-modeline-mode
|
||||
(doom-hide-modeline-mode -1))))
|
||||
(add-hook 'doom-popup-mode-hook #'doom|hide-modeline-in-popup)
|
||||
|
||||
;;
|
||||
(defun doom*popup-init (orig-fn &rest args)
|
||||
"Initializes a window as a popup window by enabling `doom-popup-mode' in it
|
||||
and setting `doom-popup-rules' within it. Returns the window."
|
||||
(unless (doom-popup-p)
|
||||
(setq doom-popup-other-window (selected-window)))
|
||||
(let* ((plist (or (nth 2 args)
|
||||
(cond ((windowp (car args))
|
||||
(shackle-match (window-buffer (car args))))
|
||||
((bufferp (car args))
|
||||
(shackle-match (car args))))))
|
||||
(buffer (get-buffer (car args)))
|
||||
(window-min-height (if (plist-get plist :modeline) 4 2))
|
||||
window)
|
||||
(when (and (doom-real-buffer-p buffer)
|
||||
(get-buffer-window-list buffer nil t))
|
||||
(setq plist (append (list :autokill t) plist))
|
||||
(setcar args (clone-indirect-buffer (buffer-name (car args)) nil t)))
|
||||
(unless (setq window (apply orig-fn args))
|
||||
(error "No popup window was found for %s: %s" (car args) plist))
|
||||
(cl-pushnew window doom-popup-windows :test #'eq)
|
||||
(with-selected-window window
|
||||
(unless (eq plist t)
|
||||
(setq-local doom-popup-rules plist))
|
||||
(doom-popup-mode +1))
|
||||
window))
|
||||
|
||||
(defun doom*popups-save (orig-fn &rest args)
|
||||
"Sets aside all popups before executing the original function, usually to
|
||||
prevent the popup(s) from messing up the UI (or vice versa)."
|
||||
(let ((in-popup-p (doom-popup-p))
|
||||
(popups (doom-popup-windows))
|
||||
(doom-popup-remember-history t))
|
||||
(when popups
|
||||
(mapc #'doom/popup-close popups))
|
||||
(unwind-protect (apply orig-fn args)
|
||||
(when popups
|
||||
(let ((origin (selected-window)))
|
||||
(doom/popup-restore)
|
||||
(unless in-popup-p
|
||||
(select-window origin)))))))
|
||||
|
||||
(defun doom*delete-popup-window (&optional window)
|
||||
"Ensure that popups are deleted properly, and killed if they have :autokill
|
||||
properties."
|
||||
(let ((window (or window (selected-window))))
|
||||
(when (doom-popup-p window)
|
||||
(setq doom-popup-windows (delq window doom-popup-windows))
|
||||
(when doom-popup-remember-history
|
||||
(setq doom-popup-history (list (doom--popup-data window))))
|
||||
(let ((autokill-p (plist-get doom-popup-rules :autokill)))
|
||||
(with-selected-window window
|
||||
(doom-popup-mode -1)
|
||||
(when autokill-p
|
||||
(kill-buffer (current-buffer))))))))
|
||||
|
||||
(advice-add #'shackle-display-buffer :around #'doom*popup-init)
|
||||
(advice-add #'balance-windows :around #'doom*popups-save)
|
||||
(advice-add #'delete-window :before #'doom*delete-popup-window)
|
||||
"Active keymap in popup windows."))
|
||||
|
||||
|
||||
;;
|
||||
@ -264,20 +154,20 @@ properties."
|
||||
;;
|
||||
|
||||
(progn ; hacks for built-in functions
|
||||
(defun doom*buffer-menu (&optional arg)
|
||||
"Open `buffer-menu' in a popup window."
|
||||
(interactive "P")
|
||||
(let ((buf (list-buffers-noselect arg)))
|
||||
(doom-popup-buffer buf)
|
||||
(with-current-buffer buf
|
||||
(setq mode-line-format "Commands: d, s, x, u; f, o, 1, 2, m, v; ~, %; q to quit; ? for help."))))
|
||||
(advice-add #'buffer-menu :override #'doom*buffer-menu)
|
||||
|
||||
(defun doom*suppress-pop-to-buffer-same-window (orig-fn &rest args)
|
||||
(cl-letf (((symbol-function 'pop-to-buffer-same-window)
|
||||
(symbol-function 'pop-to-buffer)))
|
||||
(apply orig-fn args)))
|
||||
(advice-add #'info :around #'doom*suppress-pop-to-buffer-same-window))
|
||||
(advice-add #'info :around #'doom*suppress-pop-to-buffer-same-window)
|
||||
(advice-add #'eww :around #'doom*suppress-pop-to-buffer-same-window)
|
||||
(advice-add #'eww-browse-url :around #'doom*suppress-pop-to-buffer-same-window)
|
||||
|
||||
(defun doom*popup-buffer-menu (&optional arg)
|
||||
"Open `buffer-menu' in a popup window."
|
||||
(interactive "P")
|
||||
(with-selected-window (doom-popup-buffer (list-buffers-noselect arg))
|
||||
(setq mode-line-format "Commands: d, s, x, u; f, o, 1, 2, m, v; ~, %; q to quit; ? for help.")))
|
||||
(advice-add #'buffer-menu :override #'doom*popup-buffer-menu))
|
||||
|
||||
|
||||
(after! comint
|
||||
@ -310,12 +200,12 @@ properties."
|
||||
|
||||
(after! evil
|
||||
(let ((map doom-popup-mode-map))
|
||||
(define-key map [remap evil-window-delete] #'doom/popup-close)
|
||||
(define-key map [remap evil-save-modified-and-close] #'doom/popup-close)
|
||||
(define-key map [remap evil-window-move-very-bottom] #'ignore)
|
||||
(define-key map [remap evil-window-move-very-top] #'ignore)
|
||||
(define-key map [remap evil-window-move-far-left] #'ignore)
|
||||
(define-key map [remap evil-window-move-far-right] #'ignore)
|
||||
(define-key map [remap evil-window-delete] #'doom/popup-close-maybe)
|
||||
(define-key map [remap evil-save-modified-and-close] #'doom/popup-close-maybe)
|
||||
(define-key map [remap evil-window-move-very-bottom] #'doom/popup-move-bottom)
|
||||
(define-key map [remap evil-window-move-very-top] #'doom/popup-move-top)
|
||||
(define-key map [remap evil-window-move-far-left] #'doom/popup-move-left)
|
||||
(define-key map [remap evil-window-move-far-right] #'doom/popup-move-right)
|
||||
(define-key map [remap evil-window-split] #'ignore)
|
||||
(define-key map [remap evil-window-vsplit] #'ignore))
|
||||
|
||||
@ -323,10 +213,9 @@ properties."
|
||||
"If current window is a popup, close it. If minibuffer is open, close it. If
|
||||
not in a popup, close all popups with an :autoclose property."
|
||||
(cond ((doom-popup-p)
|
||||
(unless (doom-popup-prop :noesc)
|
||||
(unless (doom-popup-property :noesc)
|
||||
(delete-window)))
|
||||
(t
|
||||
(doom/popup-close-all))))
|
||||
(t (doom/popup-close-all))))
|
||||
(add-hook '+evil-esc-hook #'doom|popup-close-maybe t)
|
||||
|
||||
;; Make evil-mode cooperate with popups
|
||||
@ -384,10 +273,10 @@ the command buffer."
|
||||
|
||||
|
||||
(after! helm
|
||||
;; Helm tries to clean up after itself, but shackle has already done this.
|
||||
;; This fixes that. To reproduce, add a helm rule in `shackle-rules', open two
|
||||
;; splits side-by-side, move to the buffer on the right and invoke helm. It
|
||||
;; will close all but the left-most buffer.
|
||||
;; Helm tries to clean up after itself, but shackle has already done this,
|
||||
;; causing problems. This fixes that. To reproduce, add a helm rule in
|
||||
;; `shackle-rules', open two splits side-by-side, move to the buffer on the
|
||||
;; right and invoke helm. It will close all but the left-most buffer.
|
||||
(setq-default helm-reuse-last-window-split-state t
|
||||
helm-split-window-in-side-p t)
|
||||
|
||||
@ -486,7 +375,7 @@ the command buffer."
|
||||
|
||||
(after! mu4e
|
||||
(defun doom*mu4e-popup-window (buf _height)
|
||||
(doom-popup-buffer buf :size 10 :noselect t)
|
||||
(doom-popup-buffer buf '(:size 10 :noselect t))
|
||||
buf)
|
||||
(advice-add #'mu4e~temp-window :override #'doom*mu4e-popup-window))
|
||||
|
||||
@ -502,7 +391,7 @@ the command buffer."
|
||||
;;
|
||||
;; By handing neotree over to shackle, which is better integrated into the
|
||||
;; rest of my config (and persp-mode), this is no longer a problem.
|
||||
(set! :popup " *NeoTree*" :align 'left :size 25)
|
||||
(set! :popup " *NeoTree*" :align neo-window-position :size neo-window-width :static t)
|
||||
|
||||
(defun +evil-neotree-display-fn (buf _alist)
|
||||
"Hand neotree off to shackle."
|
||||
@ -515,7 +404,10 @@ the command buffer."
|
||||
"Repair neotree state whenever its popup state is restored. This ensures
|
||||
that `doom*popup-save' won't break it."
|
||||
(when (equal (buffer-name) neo-buffer-name)
|
||||
(setq neo-global--window (selected-window))))
|
||||
(setq neo-global--window (selected-window))
|
||||
;; Fix neotree shrinking when closing nearby vertical splits
|
||||
(when neo-window-fixed-size
|
||||
(doom-resize-window neo-global--window neo-window-width t t))))
|
||||
(add-hook 'doom-popup-mode-hook #'+evil|neotree-fix-popup))
|
||||
|
||||
|
||||
@ -523,7 +415,7 @@ that `doom*popup-save' won't break it."
|
||||
(defun doom*persp-mode-restore-popups (&rest _)
|
||||
"Restore popup windows when loading a perspective from file."
|
||||
(dolist (window (window-list))
|
||||
(when-let (plist (window-parameter window 'popup))
|
||||
(when-let (plist (doom-popup-properties window))
|
||||
(with-selected-window window
|
||||
(unless doom-popup-mode
|
||||
(setq-local doom-popup-rules plist)
|
||||
@ -582,16 +474,16 @@ you came from."
|
||||
'("*Org Links*" :size 5 :noselect t)
|
||||
'("*Org Export Dispatcher*" :noselect t)
|
||||
'(" *Agenda Commands*" :noselect t)
|
||||
'("^\\*Org Agenda" :regexp t :size 30)
|
||||
'("^\\*Org Agenda" :regexp t :size 20)
|
||||
'("*Org Clock*" :noselect t)
|
||||
'("^\\*Org Src" :regexp t :size 0.35 :noesc t)
|
||||
'("*Edit Formulas*" :size 10)
|
||||
'("^\\*Org-Babel" :regexp t :size 25 :noselect t)
|
||||
'("^CAPTURE.*\\.org$" :regexp t :size 20))
|
||||
|
||||
;; Org has its own window management system with a scorched earth philosophy
|
||||
;; I'm not fond of. i.e. it kills all windows and monopolizes the frame. No
|
||||
;; thanks. We can do better with shackle's help.
|
||||
;; Org has a scorched-earth window management system I'm not fond of. i.e.
|
||||
;; it kills all windows and monopolizes the frame. No thanks. We can do
|
||||
;; better with shackle's help.
|
||||
(defun doom*suppress-delete-other-windows (orig-fn &rest args)
|
||||
(cl-letf (((symbol-function 'delete-other-windows)
|
||||
(symbol-function 'ignore)))
|
||||
@ -600,17 +492,17 @@ you came from."
|
||||
(advice-add #'org-capture-place-template :around #'doom*suppress-delete-other-windows)
|
||||
(advice-add #'org-export--dispatch-ui :around #'doom*suppress-delete-other-windows)
|
||||
|
||||
;; `org-edit-src-code' simply clones and narrows the buffer to a src block,
|
||||
;; so we are secretly manipulating the same buffer. Since truely killing it
|
||||
;; would kill the original org buffer we've got to do things differently.
|
||||
(defun doom*org-src-switch-to-buffer (buffer _context)
|
||||
;; Hand off the src-block window to a shackle popup window.
|
||||
(defun doom*org-src-pop-to-buffer (buffer _context)
|
||||
"Open the src-edit in a way that shackle can detect."
|
||||
(if (eq org-src-window-setup 'switch-invisibly)
|
||||
(set-buffer buffer)
|
||||
(pop-to-buffer buffer)))
|
||||
(advice-add #'org-src-switch-to-buffer :override #'doom*org-src-switch-to-buffer)
|
||||
(advice-add #'org-src-switch-to-buffer :override #'doom*org-src-pop-to-buffer)
|
||||
|
||||
;; Ensure todo, agenda, and other minor popups handed off to shackle.
|
||||
;; Ensure todo, agenda, and other minor popups are delegated to shackle.
|
||||
(defun doom*org-pop-to-buffer (&rest args)
|
||||
"Use `pop-to-buffer' instead of `switch-to-buffer' to open buffer.'"
|
||||
(let ((buf (car args)))
|
||||
(pop-to-buffer
|
||||
(cond ((stringp buf) (get-buffer-create buf))
|
||||
@ -624,15 +516,13 @@ you came from."
|
||||
|
||||
;; Hide modeline in org-agenda
|
||||
(add-hook 'org-agenda-finalize-hook #'doom-hide-modeline-mode)
|
||||
(add-hook 'org-agenda-finalize-hook #'org-fit-window-to-buffer)
|
||||
;; Don't monopolize frame!
|
||||
(advice-add #'org-agenda :around #'doom*suppress-delete-other-windows)
|
||||
|
||||
;; ensure quit keybindings work propertly
|
||||
(map! :map org-agenda-mode-map
|
||||
:m [escape] 'org-agenda-Quit
|
||||
:m "ESC" 'org-agenda-Quit)
|
||||
(let ((map org-agenda-mode-map))
|
||||
(define-key map "q" 'org-agenda-Quit)
|
||||
(define-key map "Q" 'org-agenda-Quit)))))
|
||||
:m "ESC" 'org-agenda-Quit))))
|
||||
(add-hook 'doom-init-hook #'doom|init-org-popups)
|
||||
|
||||
(provide 'core-popups)
|
||||
|
@ -10,43 +10,35 @@ state are passed in.")
|
||||
:config
|
||||
(setq projectile-cache-file (concat doom-cache-dir "projectile.cache")
|
||||
projectile-enable-caching (not noninteractive)
|
||||
projectile-file-exists-remote-cache-expire nil
|
||||
projectile-indexing-method 'alien
|
||||
projectile-known-projects-file (concat doom-cache-dir "projectile.projects")
|
||||
projectile-require-project-root nil
|
||||
projectile-project-root-files
|
||||
'(".git" ".hg" ".svn" ".project" "package.json" "setup.py" "Gemfile"
|
||||
"build.gradle")
|
||||
projectile-other-file-alist
|
||||
(append '(("less" "css")
|
||||
("styl" "css")
|
||||
("sass" "css")
|
||||
("scss" "css")
|
||||
("css" "scss" "sass" "less" "styl")
|
||||
("jade" "html")
|
||||
("pug" "html")
|
||||
("html" "jade" "pug" "jsx" "tsx"))
|
||||
projectile-other-file-alist)
|
||||
projectile-globally-ignored-file-suffixes '(".elc" ".pyc" ".o")
|
||||
projectile-globally-ignored-files '(".DS_Store" "Icon
|
||||
")
|
||||
projectile-globally-ignored-directories
|
||||
(append (list doom-local-dir ".sync")
|
||||
projectile-globally-ignored-files '(".DS_Store" "Icon
|
||||
" "TAGS")
|
||||
projectile-globally-ignored-file-suffixes '(".elc" ".pyc" ".o"))
|
||||
|
||||
;; a more generic project root file
|
||||
(push ".project" projectile-project-root-files-bottom-up)
|
||||
|
||||
(nconc projectile-globally-ignored-directories (list doom-local-dir ".sync"))
|
||||
(nconc projectile-other-file-alist '(("css" . ("scss" "sass" "less" "style"))
|
||||
("scss" . ("css"))
|
||||
("sass" . ("css"))
|
||||
("less" . ("css"))
|
||||
("styl" . ("css"))))
|
||||
|
||||
;; Projectile root-searching functions can cause an infinite loop on TRAMP
|
||||
;; connections, so disable them.
|
||||
(defun doom*projectile-locate-dominating-file (orig-fn &rest args)
|
||||
(defun doom*projectile-locate-dominating-file (orig-fn &rest args)
|
||||
"Don't traverse the file system if on a remote connection."
|
||||
(unless (file-remote-p default-directory)
|
||||
(apply orig-fn args)))
|
||||
(advice-add #'projectile-locate-dominating-file :around #'doom*projectile-locate-dominating-file)
|
||||
|
||||
(defun doom*projectile-cache-current-file (orig-fun &rest args)
|
||||
"Don't cache ignored files."
|
||||
(unless (cl-some (lambda (path)
|
||||
(string-prefix-p buffer-file-name
|
||||
(expand-file-name path)))
|
||||
"Don't cache ignored files."
|
||||
(unless (cl-loop for path in (projectile-ignored-directories)
|
||||
if (string-prefix-p buffer-file-name (expand-file-name path))
|
||||
return t)
|
||||
(apply orig-fun args)))
|
||||
(advice-add #'projectile-cache-current-file :around #'doom*projectile-cache-current-file))
|
||||
@ -55,26 +47,34 @@ state are passed in.")
|
||||
;;
|
||||
;; Library
|
||||
;;
|
||||
|
||||
|
||||
(defun doom/reload-project ()
|
||||
"Reload the project root cache."
|
||||
(interactive)
|
||||
(projectile-invalidate-cache nil)
|
||||
(projectile-reset-cached-project-root)
|
||||
(dolist (fn projectile-project-root-files-functions)
|
||||
(remhash (format "%s-%s" fn default-directory) projectile-project-root-cache)))
|
||||
|
||||
(defun doom-project-p ()
|
||||
"Whether or not this buffer is currently in a project or not."
|
||||
"Whether or not this buffer is currently in a project or not."
|
||||
(let ((projectile-require-project-root t))
|
||||
(projectile-project-p)))
|
||||
|
||||
(defun doom-project-root (&optional strict-p)
|
||||
"Get the path to the root of your project."
|
||||
(let ((projectile-require-project-root strict-p))
|
||||
|
||||
(defun doom-project-root ()
|
||||
"Get the path to the root of your project.
|
||||
If STRICT-P, return nil if no project was found, otherwise return
|
||||
`default-directory'."
|
||||
(let (projectile-require-project-root)
|
||||
(projectile-project-root)))
|
||||
|
||||
(defun doom*project-root (&rest _)
|
||||
"An advice function used to replace project-root-detection functions in other
|
||||
libraries."
|
||||
|
||||
(defalias 'doom-project-expand #'projectile-expand-root)
|
||||
|
||||
(defmacro doom-project-has! (files)
|
||||
"Checks if the project has the specified FILES, relative to the project root,
|
||||
unless the path begins with ./ or ../, in which case it's relative to
|
||||
`default-directory'. Recognizes (and ...) and/or (or ...) forms."
|
||||
(defmacro doom-project-has! (files)
|
||||
"Checks if the project has the specified FILES.
|
||||
Paths are relative to the project root, unless they start with ./ or ../ (in
|
||||
which case they're relative to `default-directory'). If they start with a slash,
|
||||
they are absolute."
|
||||
(doom--resolve-path-forms files (doom-project-root)))
|
||||
|
||||
|
||||
@ -82,21 +82,22 @@ unless the path begins with ./ or ../, in which case it's relative to
|
||||
;; Projects
|
||||
;;
|
||||
|
||||
(defvar-local doom-project nil
|
||||
(defvar-local doom-project nil
|
||||
"A list of project mode to enable. Used for .dir-locals.el.")
|
||||
|
||||
(defun doom|autoload-project-mode ()
|
||||
"Auto-enable projects listed in `doom-project', which is meant to be set from
|
||||
.dir-locals.el files."
|
||||
(dolist (mode doom-project)
|
||||
.dir-locals.el files."
|
||||
(cl-loop for mode in doom-project
|
||||
unless (symbol-value mode)
|
||||
do (funcall mode)))
|
||||
(add-hook 'after-change-major-mode-hook #'doom|autoload-project-mode)
|
||||
|
||||
(defmacro def-project-mode! (name &rest plist)
|
||||
"Define a project minor-mode named NAME and declare where and how it is
|
||||
activated. Project modes allow you to configure 'sub-modes' for major-modes that
|
||||
are specific to a specific folder, certain project structure, framework or
|
||||
arbitrary context you define. These project modes can have their own settings,
|
||||
(defmacro def-project-mode! (name &rest plist)
|
||||
"Define a project minor-mode named NAME (a symbol) and declare where and how
|
||||
it is activated. Project modes allow you to configure 'sub-modes' for
|
||||
major-modes that are specific to a specific folder, certain project structure,
|
||||
framework or arbitrary context you define. These project modes can have their
|
||||
own settings, keymaps, hooks, snippets, etc.
|
||||
|
||||
This creates NAME-hook and NAME-map as well.
|
||||
@ -118,34 +119,52 @@ should be activated. If they are *all* true, NAME is activated.
|
||||
|
||||
:when PREDICATE -- if PREDICATE returns true (can be a form or the symbol of a
|
||||
function)
|
||||
|
||||
|
||||
:add-hooks HOOKS -- HOOKS is a list of hooks to add this mode's hook.
|
||||
|
||||
:on-load FORM -- FORM to run the first time this project mode is enabled.
|
||||
|
||||
:on-enter FORM -- FORM is run each time the mode is activated.
|
||||
|
||||
:on-exit FORM -- FORM is run each time the mode is disabled.
|
||||
|
||||
Relevant: `doom-project-hook'."
|
||||
(declare (indent 1))
|
||||
Relevant: `doom-project-hook'."
|
||||
(declare (indent 1) (doc-string 2))
|
||||
(let ((doc-string (if (stringp (car plist))
|
||||
(prog1 (car plist)
|
||||
(setq plist (cdr plist)))
|
||||
"A project minor mode."))
|
||||
(modes (plist-get plist :modes))
|
||||
(files (plist-get plist :files))
|
||||
(when (plist-get plist :when))
|
||||
(match (plist-get plist :match))
|
||||
(init-form (plist-get plist :init))
|
||||
(match (plist-get plist :match))
|
||||
(hooks (plist-get plist :add-hooks))
|
||||
(load-form (plist-get plist :on-load))
|
||||
(enter-form (plist-get plist :on-enter))
|
||||
(exit-form (plist-get plist :on-exit))
|
||||
(init-var (intern (format "%s-init" name))))
|
||||
`(progn
|
||||
(defvar ,keymap-sym (make-sparse-keymap)
|
||||
`(progn
|
||||
,(if load-form `(defvar ,init-var nil))
|
||||
(define-minor-mode ,name
|
||||
(define-minor-mode ,name
|
||||
,doc-string
|
||||
:init-value nil
|
||||
:init-value nil
|
||||
:lighter ""
|
||||
:keymap (make-sparse-keymap)
|
||||
(if (not ,name)
|
||||
,exit-form
|
||||
(run-hook-with-args 'doom-project-hook ',name)
|
||||
,(when load-form
|
||||
`(unless ,init-var
|
||||
,load-form
|
||||
(setq ,init-var t)))
|
||||
,enter-form))
|
||||
,(when hooks
|
||||
`(setq ,(intern (format "%s-hook" name)) ',hooks))
|
||||
,(when (or modes match files when)
|
||||
`(associate! ,name
|
||||
:modes ,modes
|
||||
:match ,match
|
||||
:files ,files
|
||||
:when ,when))
|
||||
(add-hook! ,name
|
||||
(run-hook-with-args 'doom-project-hook ',name))
|
||||
,(when init-form
|
||||
`(add-transient-hook! ',(intern (format "%s-hook" name))
|
||||
:files ,files
|
||||
:when ,when)))))
|
||||
|
||||
(provide 'core-projects)
|
||||
|
@ -34,22 +34,32 @@ shorter major mode name in the mode-line. See `doom|set-mode-name'.")
|
||||
|
||||
;; Settings
|
||||
(def-setting! :theme (theme)
|
||||
"Sets the current THEME (a symbol)."
|
||||
`(unless doom-theme
|
||||
(setq doom-theme ,theme)))
|
||||
|
||||
(def-setting! :font (family &rest spec)
|
||||
"Sets the default font (if one wasn't already set). FAMILY is the name of the
|
||||
font, and SPEC is a `font-spec'."
|
||||
`(unless doom-font
|
||||
(setq doom-font (font-spec :family ,family ,@spec))))
|
||||
|
||||
(def-setting! :variable-pitch-font (family &rest spec)
|
||||
"Sets the default font for the variable-pitch face and minor mode (if one
|
||||
wasn't already set). FAMILY is the name of the font, and SPEC is a `font-spec'."
|
||||
`(unless doom-variable-pitch-font
|
||||
(setq doom-variable-pitch-font (font-spec :family ,family ,@spec))))
|
||||
|
||||
(def-setting! :big-font (family &rest spec)
|
||||
"Sets the font to use for `doom-big-font-mode' (if one wasn't already set).
|
||||
FAMILY is the name of the font, and SPEC is a `font-spec'."
|
||||
`(unless doom-big-font
|
||||
(setq doom-big-font (font-spec :family ,family ,@spec))))
|
||||
|
||||
(def-setting! :unicode-font (family &rest spec)
|
||||
"Sets the font to use for unicode characters (if one wasn't already set).
|
||||
FAMILY is the name of the font, and SPEC is a `font-spec'. This is ignored if
|
||||
the ':ui unicode' module is enabled."
|
||||
`(unless doom-unicode-font
|
||||
(setq doom-unicode-font (font-spec :family ,family ,@spec))))
|
||||
|
||||
@ -169,12 +179,9 @@ local value, whether or not it's permanent-local. Therefore, we cycle
|
||||
"Set the major mode's `mode-name', as dictated by `doom-major-mode-names'."
|
||||
(when-let (name (cdr (assq major-mode doom-major-mode-names)))
|
||||
(setq mode-name
|
||||
(cond ((functionp name)
|
||||
(funcall name))
|
||||
((stringp name)
|
||||
name)
|
||||
(t
|
||||
(error "'%s' isn't a valid name for %s" name major-mode))))))
|
||||
(cond ((functionp name) (funcall name))
|
||||
((stringp name) name)
|
||||
(t (error "'%s' isn't a valid name for %s" name major-mode))))))
|
||||
(add-hook 'after-change-major-mode-hook #'doom|set-mode-name)
|
||||
|
||||
|
||||
@ -227,7 +234,7 @@ local value, whether or not it's permanent-local. Therefore, we cycle
|
||||
|
||||
;; prompts the user for confirmation when deleting a non-empty frame
|
||||
(define-key global-map [remap delete-frame] #'doom/delete-frame)
|
||||
;; buffer name in frame title
|
||||
;; simple name in frame title
|
||||
(setq-default frame-title-format '("DOOM Emacs"))
|
||||
;; auto-enabled in Emacs 25+; I'll do it myself
|
||||
(global-eldoc-mode -1)
|
||||
@ -273,6 +280,7 @@ local value, whether or not it's permanent-local. Therefore, we cycle
|
||||
:commands (fringe-helper-define fringe-helper-convert)
|
||||
:init
|
||||
(unless (fboundp 'define-fringe-bitmap)
|
||||
;; doesn't exist in terminal Emacs; define it to prevent errors
|
||||
(defun define-fringe-bitmap (&rest _))))
|
||||
|
||||
(def-package! hideshow ; built-in
|
||||
@ -310,13 +318,6 @@ local value, whether or not it's permanent-local. Therefore, we cycle
|
||||
:config (setq rainbow-delimiters-max-face-count 3)
|
||||
:init (add-hook 'lisp-mode-hook #'rainbow-delimiters-mode))
|
||||
|
||||
;; indicators for empty lines past EOF
|
||||
(def-package! vi-tilde-fringe
|
||||
:commands (global-vi-tilde-fringe-mode vi-tilde-fringe-mode)
|
||||
:init
|
||||
(add-hook 'doom-init-ui-hook #'global-vi-tilde-fringe-mode)
|
||||
(defun doom|disable-vi-tilde-fringe () (vi-tilde-fringe-mode -1)))
|
||||
|
||||
;; For a distractions-free-like UI, that dynamically resizes margets and can
|
||||
;; center a buffer.
|
||||
(def-package! visual-fill-column
|
||||
|
@ -8,14 +8,16 @@
|
||||
;; doom:... an evil operator, motion or command
|
||||
;; doom|... hook function
|
||||
;; doom*... advising functions
|
||||
;; doom@... a hydra command
|
||||
;; ...! a macro or function that configures DOOM
|
||||
;; =... an interactive command that starts an app module
|
||||
;; %... functions used for in-snippet logic
|
||||
;; +... Any of the above but part of a module, e.g. `+emacs-lisp|init-hook'
|
||||
;;
|
||||
;; Autoloaded functions are in core/autoload/*.el and modules/*/*/autoload.el or
|
||||
;; modules/*/*/autoload/*.el.
|
||||
|
||||
(defvar doom-version "2.0.5"
|
||||
(defvar doom-version "2.0.6"
|
||||
"Current version of DOOM emacs.")
|
||||
|
||||
(defvar doom-debug-mode (or (getenv "DEBUG") init-file-debug)
|
||||
@ -61,8 +63,7 @@ problems.")
|
||||
(defvar doom-packages-dir (concat doom-local-dir "packages/")
|
||||
"Where package.el and quelpa plugins (and their caches) are stored.")
|
||||
|
||||
(defvar doom-autoload-file
|
||||
(concat doom-local-dir "autoloads.el")
|
||||
(defvar doom-autoload-file (concat doom-local-dir "autoloads.el")
|
||||
"Location of the autoloads file generated by `doom/reload-autoloads'.")
|
||||
|
||||
(defgroup doom nil
|
||||
|
@ -22,7 +22,6 @@
|
||||
(package! nlinum-hl)
|
||||
(package! nlinum-relative))
|
||||
(package! rainbow-delimiters)
|
||||
(package! vi-tilde-fringe)
|
||||
(package! visual-fill-column)
|
||||
|
||||
;; core-popups.el
|
||||
@ -36,8 +35,6 @@
|
||||
(package! editorconfig)
|
||||
(package! expand-region)
|
||||
(package! help-fns+)
|
||||
(package! imenu-anywhere)
|
||||
(package! imenu-list)
|
||||
(package! pcre2el)
|
||||
(package! smart-forward)
|
||||
(package! smartparens)
|
||||
@ -49,3 +46,4 @@
|
||||
|
||||
;; core-keybinds.el
|
||||
(package! which-key)
|
||||
(package! hydra)
|
||||
|
@ -3,18 +3,18 @@
|
||||
|
||||
;; --- Helpers ----------------------------
|
||||
|
||||
;; `doom--resolve-paths'
|
||||
(def-test! resolve-paths
|
||||
;; `doom--resolve-path-forms'
|
||||
(def-test! resolve-path-forms
|
||||
(should
|
||||
(equal (doom--resolve-paths '(and "fileA" "fileB"))
|
||||
(equal (doom--resolve-path-forms '(and "fileA" "fileB"))
|
||||
'(and (file-exists-p (expand-file-name "fileA" (doom-project-root)))
|
||||
(file-exists-p (expand-file-name "fileB" (doom-project-root)))))))
|
||||
|
||||
;; `doom--resolve-hooks'
|
||||
(def-test! resolve-hooks
|
||||
(should (equal (doom--resolve-hooks '(js2-mode haskell-mode))
|
||||
;; `doom--resolve-hook-forms'
|
||||
(def-test! resolve-hook-forms
|
||||
(should (equal (doom--resolve-hook-forms '(js2-mode haskell-mode))
|
||||
'(js2-mode-hook haskell-mode-hook)))
|
||||
(should (equal (doom--resolve-hooks '(quote (js2-mode-hook haskell-mode-hook)))
|
||||
(should (equal (doom--resolve-hook-forms '(quote (js2-mode-hook haskell-mode-hook)))
|
||||
'(js2-mode-hook haskell-mode-hook))))
|
||||
|
||||
;; `doom-unquote'
|
||||
@ -32,6 +32,48 @@
|
||||
(should (equal (doom-enlist 'a) '(a)))
|
||||
(should (equal (doom-enlist '(a)) '(a))))
|
||||
|
||||
;; `doom-resolve-vim-path'
|
||||
(def-test! resolve-vim-path
|
||||
(cl-flet ((do-it #'doom-resolve-vim-path))
|
||||
;; file modifiers
|
||||
(let ((buffer-file-name "~/.emacs.d/test/modules/feature/test-evil.el")
|
||||
(default-directory "~/.emacs.d/test/modules/"))
|
||||
(should (equal (do-it "%") "feature/test-evil.el"))
|
||||
(should (equal (do-it "%:r") "feature/test-evil"))
|
||||
(should (equal (do-it "%:r.elc") "feature/test-evil.elc"))
|
||||
(should (equal (do-it "%:e") "el"))
|
||||
(should (equal (do-it "%:p") (expand-file-name buffer-file-name)))
|
||||
(should (equal (do-it "%:h") "feature"))
|
||||
(should (equal (do-it "%:t") "test-evil.el"))
|
||||
(should (equal (do-it "%:.") "feature/test-evil.el"))
|
||||
(should (equal (do-it "%:~") "~/.emacs.d/test/modules/feature/test-evil.el"))
|
||||
(should (equal (file-truename (do-it "%:p"))
|
||||
(file-truename buffer-file-name))))
|
||||
;; nested file modifiers
|
||||
(let ((buffer-file-name "~/vim/src/version.c")
|
||||
(default-directory "~/vim/"))
|
||||
(should (equal (do-it "%:p") (expand-file-name "~/vim/src/version.c")))
|
||||
(should (equal (do-it "%:p:.") "src/version.c"))
|
||||
(should (equal (do-it "%:p:~") "~/vim/src/version.c"))
|
||||
(should (equal (do-it "%:h") "src"))
|
||||
(should (equal (do-it "%:p:h") (expand-file-name "~/vim/src")))
|
||||
(should (equal (do-it "%:p:h:h") (expand-file-name "~/vim")))
|
||||
(should (equal (do-it "%:t") "version.c"))
|
||||
(should (equal (do-it "%:p:t") "version.c"))
|
||||
(should (equal (do-it "%:r") "src/version"))
|
||||
(should (equal (do-it "%:p:r") (expand-file-name "~/vim/src/version")))
|
||||
(should (equal (do-it "%:t:r") "version")))
|
||||
;; empty file modifiers
|
||||
(let (buffer-file-name default-directory)
|
||||
(should (equal (do-it "%") ""))
|
||||
(should (equal (do-it "%:r") ""))
|
||||
(should (equal (do-it "%:e") ""))
|
||||
(should (equal (do-it "%:h") ""))
|
||||
(should (equal (do-it "%:t") ""))
|
||||
(should (equal (do-it "%:.") ""))
|
||||
(should (equal (do-it "%:~") ""))
|
||||
(should (equal (do-it "%:P") "")))))
|
||||
|
||||
|
||||
;; --- Macros -----------------------------
|
||||
|
||||
|
@ -30,17 +30,17 @@
|
||||
(require 'core (concat user-emacs-directory "core/core"))
|
||||
|
||||
(doom! :feature
|
||||
;debugger ; FIXME stepping through code, to help you add bugs
|
||||
eval ; run code, run (also, repls)
|
||||
evil ; come to the dark side, we have cookies
|
||||
jump ; helping you get around
|
||||
snippets ; my elves. They type so I don't have to
|
||||
file-templates ; auto-snippets for empty files
|
||||
hydra ; keybindings that stick around
|
||||
jump ; helping you get around
|
||||
services ; TODO managing external services & code builders
|
||||
snippets ; my elves. They type so I don't have to
|
||||
spellcheck ; tasing you for misspelling mispelling
|
||||
syntax-checker ; tasing you for every semicolon you forget
|
||||
version-control ; remember, remember that commit in November
|
||||
workspaces ; tab emulation, persistence & separate workspaces
|
||||
eval ; repls, runners 'n builders; run code, run
|
||||
;debug ; FIXME stepping through code, to help you add bugs
|
||||
|
||||
:completion
|
||||
company ; the ultimate code completion backend
|
||||
@ -58,55 +58,57 @@
|
||||
evil-goggles ; display visual hints when editing in evil
|
||||
;unicode ; extended unicode support for various languages
|
||||
;tabbar ; FIXME an (incomplete) tab bar for Emacs
|
||||
vi-tilde-fringe ; fringe tildes to mark beyond EOB
|
||||
|
||||
:tools
|
||||
dired ; making dired pretty [functional]
|
||||
electric-indent ; smarter, keyword-based electric-indent
|
||||
eshell ; a consistent, cross-platform shell (WIP)
|
||||
gist ; interacting with github gists
|
||||
imenu ; an imenu sidebar and searchable code index
|
||||
impatient-mode ; show off code over HTTP
|
||||
;macos ; MacOS-specific commands
|
||||
make ; run make tasks from Emacs
|
||||
neotree ; a project drawer, like NERDTree for vim
|
||||
password-store ; password manager for nerds
|
||||
prodigy ; manage external services from within emacs
|
||||
rotate-text ; cycle region at point between text candidates
|
||||
term ; terminals in Emacs
|
||||
tmux ; an API for interacting with tmux
|
||||
upload ; map local to remote projects via ssh/ftp
|
||||
|
||||
:lang
|
||||
;assembly ; assembly for fun or debugging
|
||||
;cc ; C/C++/Obj-C madness
|
||||
;crystal ; ruby at the speed of c
|
||||
;csharp ; unity, .NET, and mono shenanigans
|
||||
;data ; config/data formats
|
||||
;elixir ; erlang done right
|
||||
;elm ; care for a cup of TEA?
|
||||
assembly ; assembly for fun or debugging
|
||||
cc ; C/C++/Obj-C madness
|
||||
crystal ; ruby at the speed of c
|
||||
csharp ; unity, .NET, and mono shenanigans
|
||||
data ; config/data formats
|
||||
elixir ; erlang done right
|
||||
elm ; care for a cup of TEA?
|
||||
emacs-lisp ; drown in parentheses
|
||||
;go ; the hipster dialect
|
||||
;haskell ; a language that's lazier than I am
|
||||
;hy ; readability of scheme w/ speed of python
|
||||
;java ; the poster child for carpal tunnel syndrome
|
||||
;javascript ; all(hope(abandon(ye(who(enter(here))))))
|
||||
;julia ; a better, faster MATLAB
|
||||
;latex ; writing papers in Emacs has never been so fun
|
||||
;ledger ; an accounting system in Emacs
|
||||
;lua ; one-based indices? one-based indices
|
||||
;markdown ; writing docs for people to ignore
|
||||
;ocaml ; an objective camel
|
||||
;perl ; write code no one else can comprehend
|
||||
;php ; make php less awful to work with
|
||||
;plantuml ; diagrams for confusing people more
|
||||
;purescript ; javascript, but functional
|
||||
;python ; beautiful is better than ugly
|
||||
;rest ; Emacs as a REST client
|
||||
;ruby ; 1.step do {|i| p "Ruby is #{i.even? ? 'love' : 'life'}"}
|
||||
;rust ; Fe2O3.unwrap().unwrap().unwrap().unwrap()
|
||||
;scala ; java, but good
|
||||
;sh ; she sells (ba|z)sh shells on the C xor
|
||||
;swift ; who asked for emoji variables?
|
||||
;typescript ; javascript, but better
|
||||
;web ; the tubes
|
||||
go ; the hipster dialect
|
||||
(haskell +intero) ; a language that's lazier than I am
|
||||
hy ; readability of scheme w/ speed of python
|
||||
(java +meghanada) ; the poster child for carpal tunnel syndrome
|
||||
javascript ; all(hope(abandon(ye(who(enter(here))))))
|
||||
julia ; a better, faster MATLAB
|
||||
latex ; writing papers in Emacs has never been so fun
|
||||
ledger ; an accounting system in Emacs
|
||||
lua ; one-based indices? one-based indices
|
||||
markdown ; writing docs for people to ignore
|
||||
ocaml ; an objective camel
|
||||
perl ; write code no one else can comprehend
|
||||
php ; make php less awful to work with
|
||||
plantuml ; diagrams for confusing people more
|
||||
purescript ; javascript, but functional
|
||||
python ; beautiful is better than ugly
|
||||
rest ; Emacs as a REST client
|
||||
ruby ; 1.step do {|i| p "Ruby is #{i.even? ? 'love' : 'life'}"}
|
||||
rust ; Fe2O3.unwrap().unwrap().unwrap().unwrap()
|
||||
scala ; java, but good
|
||||
sh ; she sells (ba|z)sh shells on the C xor
|
||||
swift ; who asked for emoji variables?
|
||||
typescript ; javascript, but better
|
||||
web ; the tubes
|
||||
|
||||
:org
|
||||
org ; organize your plain life in plain text
|
||||
@ -114,7 +116,6 @@
|
||||
org-attach ; a simpler attachment system
|
||||
org-capture ; a better org-capture, in or outside of Emacs
|
||||
org-export ; a custom, centralized export system
|
||||
org-notebook ; org-mode as a notebook
|
||||
org-present ; using org-mode for presentations
|
||||
;org-sync ; TODO sync with mobile
|
||||
;org-publish ; TODO org + blogs
|
||||
@ -130,7 +131,6 @@
|
||||
write ; emacs as a word processor (latex + org + markdown)
|
||||
|
||||
;; Private modules named after your username are loaded automatically.
|
||||
;; Leaving this here is harmless though. Also, they are omitted from
|
||||
;; source control (except for mine; use it as a reference).
|
||||
;; Leaving this here is harmless though.
|
||||
:private hlissner)
|
||||
|
||||
|
@ -15,5 +15,8 @@
|
||||
:lang
|
||||
web
|
||||
|
||||
:org
|
||||
org
|
||||
|
||||
:private
|
||||
hlissner)
|
||||
|
@ -26,9 +26,11 @@
|
||||
(all-files-p +ivy--file-search-all-files-p)
|
||||
(query
|
||||
(or query
|
||||
(if (evil-visual-state-p)
|
||||
(and beg end
|
||||
(> (abs (- end beg)) 1)
|
||||
(rxt-quote-pcre (buffer-substring-no-properties beg end)))
|
||||
+ivy--file-last-search)
|
||||
+ivy--file-last-search))
|
||||
(prompt
|
||||
(format "%s%%s %s"
|
||||
|
@ -10,9 +10,8 @@
|
||||
face to render it with.")
|
||||
|
||||
(defmacro +ivy-do-action! (action)
|
||||
"A factory function that returns an interactive lamba that sets the current
|
||||
ivy action and immediately runs it on the current candidate (ending the ivy
|
||||
session)."
|
||||
"Returns an interactive lambda that sets the current ivy action and
|
||||
immediately runs it on the current candidate (ending the ivy session)."
|
||||
`(lambda ()
|
||||
(interactive)
|
||||
(ivy-set-action ,action)
|
||||
@ -63,10 +62,10 @@ session)."
|
||||
[remap describe-face] #'counsel-describe-face)
|
||||
|
||||
;; Show more buffer information in switch-buffer commands
|
||||
(ivy-set-display-transformer 'ivy-switch-buffer #'+ivy-buffer-transformer)
|
||||
(ivy-set-display-transformer 'ivy-switch-buffer-other-window #'+ivy-buffer-transformer)
|
||||
(ivy-set-display-transformer '+ivy/switch-workspace-buffer #'+ivy-buffer-transformer)
|
||||
(ivy-set-display-transformer 'counsel-recentf #'abbreviate-file-name)
|
||||
(ivy-set-display-transformer #'ivy-switch-buffer #'+ivy-buffer-transformer)
|
||||
(ivy-set-display-transformer #'ivy-switch-buffer-other-window #'+ivy-buffer-transformer)
|
||||
(ivy-set-display-transformer #'+ivy/switch-workspace-buffer #'+ivy-buffer-transformer)
|
||||
(ivy-set-display-transformer #'counsel-recentf #'abbreviate-file-name)
|
||||
|
||||
(when (featurep! :feature workspaces)
|
||||
(nconc ivy-sort-functions-alist
|
||||
@ -111,3 +110,51 @@ session)."
|
||||
(setq smex-save-file (concat doom-cache-dir "/smex-items"))
|
||||
(smex-initialize))
|
||||
|
||||
|
||||
(def-package! ivy-hydra
|
||||
:commands (+ivy@coo/body ivy-dispatching-done-hydra)
|
||||
:init
|
||||
(map! :map ivy-minibuffer-map
|
||||
"C-o" #'+ivy@coo/body
|
||||
"M-o" #'ivy-dispatching-done-hydra)
|
||||
:config
|
||||
(def-hydra! +ivy@coo (:hint nil :color pink)
|
||||
"
|
||||
Move ^^^^^^^^^^ | Call ^^^^ | Cancel^^ | Options^^ | Action _w_/_s_/_a_: %s(ivy-action-name)
|
||||
----------^^^^^^^^^^-+--------------^^^^-+-------^^-+--------^^-+---------------------------------
|
||||
_g_ ^ ^ _k_ ^ ^ _u_ | _f_orward _o_ccur | _i_nsert | _c_alling: %-7s(if ivy-calling \"on\" \"off\") _C_ase-fold: %-10`ivy-case-fold-search
|
||||
^↨^ _h_ ^+^ _l_ ^↕^ | _RET_ done ^^ | _q_uit | _m_atcher: %-7s(ivy--matcher-desc) _t_runcate: %-11`truncate-lines
|
||||
_G_ ^ ^ _j_ ^ ^ _d_ | _TAB_ alt-done ^^ | ^ ^ | _<_/_>_: shrink/grow
|
||||
"
|
||||
;; arrows
|
||||
("j" ivy-next-line)
|
||||
("k" ivy-previous-line)
|
||||
("l" ivy-alt-done)
|
||||
("h" ivy-backward-delete-char)
|
||||
("g" ivy-beginning-of-buffer)
|
||||
("G" ivy-end-of-buffer)
|
||||
("d" ivy-scroll-up-command)
|
||||
("u" ivy-scroll-down-command)
|
||||
("e" ivy-scroll-down-command)
|
||||
;; actions
|
||||
("q" keyboard-escape-quit :exit t)
|
||||
("C-g" keyboard-escape-quit :exit t)
|
||||
("<escape>" keyboard-escape-quit :exit t)
|
||||
("C-o" nil)
|
||||
("i" nil)
|
||||
("TAB" ivy-alt-done :exit nil)
|
||||
("C-j" ivy-alt-done :exit nil)
|
||||
;; ("d" ivy-done :exit t)
|
||||
("RET" ivy-done :exit t)
|
||||
("C-m" ivy-done :exit t)
|
||||
("f" ivy-call)
|
||||
("c" ivy-toggle-calling)
|
||||
("m" ivy-toggle-fuzzy)
|
||||
(">" ivy-minibuffer-grow)
|
||||
("<" ivy-minibuffer-shrink)
|
||||
("w" ivy-prev-action)
|
||||
("s" ivy-next-action)
|
||||
("a" ivy-read-action)
|
||||
("t" (setq truncate-lines (not truncate-lines)))
|
||||
("C" ivy-toggle-case-fold)
|
||||
("o" ivy-occur :exit t)))
|
||||
|
@ -6,3 +6,4 @@
|
||||
(package! counsel-projectile)
|
||||
(package! smex)
|
||||
(package! swiper)
|
||||
(package! ivy-hydra)
|
||||
|
@ -1,9 +0,0 @@
|
||||
;;; feature/debug/autoload/debug.el -*- lexical-binding: t; -*-
|
||||
|
||||
;;;###autoload
|
||||
(defun +debug/quit ()
|
||||
(interactive)
|
||||
(ignore-errors (call-interactively 'realgud:cmd-quit))
|
||||
(doom/popup-close)
|
||||
(evil-normal-state))
|
||||
|
@ -1,31 +0,0 @@
|
||||
;;; feature/debug/autoload/evil.el -*- lexical-binding: t; -*-
|
||||
|
||||
;;;###autoload (autoload '+debug:run "feature/debug/autoload/evil" nil t)
|
||||
(evil-define-command +debug:run (&optional path)
|
||||
"Initiate debugger for current major mode"
|
||||
(interactive "<f>")
|
||||
(let ((default-directory (doom-project-root)))
|
||||
(cond ((memq major-mode '(c-mode c++-mode))
|
||||
(realgud:gdb (if path (concat "gdb " path))))
|
||||
((memq major-mode '(ruby-mode enh-ruby-mode))
|
||||
(doom:repl nil (format "run '%s'" (file-name-nondirectory (or path buffer-file-name)))))
|
||||
((eq major-mode 'sh-mode)
|
||||
(let ((shell sh-shell))
|
||||
(when (string= shell "sh")
|
||||
(setq shell "bash"))
|
||||
(cond ((string= shell "bash")
|
||||
(realgud:bashdb (if path (concat "bashdb " path))))
|
||||
((string= shell "zsh")
|
||||
(realgud:zshdb (if path (concat "zshdb " path))))
|
||||
(t (user-error "No shell debugger for %s" shell)))))
|
||||
;; TODO Add python debugging
|
||||
((memq major-mode '(js-mode js2-mode js3-mode))
|
||||
(realgud:trepanjs))
|
||||
((eq major-mode 'haskell-mode)
|
||||
(haskell-debug))
|
||||
(t (user-error "No debugger for %s" major-mode)))))
|
||||
|
||||
;;;###autoload (autoload '+debug:toggle-breakpoint "feature/debug/autoload/evil" nil t)
|
||||
(evil-define-command +debug:toggle-breakpoint (&optional bang)
|
||||
(interactive "<!>")
|
||||
(call-interactively (if bang 'realgud:cmd-clear 'realgud:cmd-break)))
|
11
modules/feature/debugger/autoload/debug.el
Normal file
11
modules/feature/debugger/autoload/debug.el
Normal file
@ -0,0 +1,11 @@
|
||||
;;; feature/debugger/autoload/debug.el -*- lexical-binding: t; -*-
|
||||
|
||||
;;;###autoload
|
||||
(defun +debugger/quit ()
|
||||
"Quit the active debugger, if any."
|
||||
(interactive)
|
||||
(ignore-errors (call-interactively #'realgud:cmd-quit))
|
||||
(doom/popup-close)
|
||||
(when (featurep 'evil)
|
||||
(evil-normal-state)))
|
||||
|
33
modules/feature/debugger/autoload/evil.el
Normal file
33
modules/feature/debugger/autoload/evil.el
Normal file
@ -0,0 +1,33 @@
|
||||
;;; feature/debugger/autoload/evil.el -*- lexical-binding: t; -*-
|
||||
|
||||
;;;###autoload (autoload '+debugger:start "feature/debugger/autoload/evil" nil t)
|
||||
(evil-define-command +debugger:start (&optional path)
|
||||
"Initiate debugger for current major mode"
|
||||
(interactive "<f>")
|
||||
;; TODO Add python debugging
|
||||
(let ((default-directory (doom-project-root)))
|
||||
(pcase major-mode
|
||||
((or 'c-mode 'c++-mode)
|
||||
(realgud:gdb (if path (concat "gdb " path))))
|
||||
((or 'ruby-mode 'enh-ruby-mode)
|
||||
;; FIXME
|
||||
(doom:repl nil (format "run '%s'" (file-name-nondirectory (or path buffer-file-name)))))
|
||||
('sh-mode
|
||||
(let ((shell sh-shell))
|
||||
(when (string= shell "sh")
|
||||
(setq shell "bash"))
|
||||
(pcase shell
|
||||
("bash"
|
||||
(realgud:bashdb (if path (concat "bashdb " path))))
|
||||
("zsh"
|
||||
(realgud:zshdb (if path (concat "zshdb " path))))
|
||||
(_ (user-error "No shell debugger for %s" shell)))))
|
||||
((or 'js-mode 'js2-mode 'js3-mode)
|
||||
(realgud:trepanjs))
|
||||
('haskell-mode (haskell-debug))
|
||||
(_ (user-error "No debugger for %s" major-mode)))))
|
||||
|
||||
;;;###autoload (autoload '+debugger:toggle-breakpoint "feature/debugger/autoload/evil" nil t)
|
||||
(evil-define-command +debugger:toggle-breakpoint (&optional bang)
|
||||
(interactive "<!>")
|
||||
(call-interactively (if bang #'realgud:cmd-clear #'realgud:cmd-break)))
|
@ -1,4 +1,4 @@
|
||||
;;; feature/debug/config.el -*- lexical-binding: t; -*-
|
||||
;;; feature/debugger/config.el -*- lexical-binding: t; -*-
|
||||
|
||||
(def-package! realgud
|
||||
:commands (realgud:gdb realgud:trepanjs realgud:bashdb realgud:zshdb)
|
||||
@ -19,7 +19,7 @@
|
||||
;; Monkey-patch `realgud:run-process' to run in a popup.
|
||||
;; TODO Find a more elegant solution
|
||||
;; FIXME Causes realgud:cmd-* to focus popup on every invocation
|
||||
(defun +debug*realgud-run-process
|
||||
(defun +debugger*realgud-run-process
|
||||
(debugger-name script-filename cmd-args minibuffer-history-var &optional no-reset)
|
||||
(let* ((cmd-buf (apply #'realgud-exec-shell debugger-name script-filename
|
||||
(car cmd-args) no-reset (cdr cmd-args)))
|
||||
@ -42,5 +42,5 @@
|
||||
(if cmd-buf (switch-to-buffer cmd-buf))
|
||||
(message "Error running command: %s" (mapconcat #'identity cmd-args " "))))
|
||||
cmd-buf))
|
||||
(advice-add #'realgud:run-process :override #'+debug*realgud-run-process))
|
||||
(advice-add #'realgud:run-process :override #'+debugger*realgud-run-process))
|
||||
|
@ -1,4 +1,4 @@
|
||||
;; -*- no-byte-compile: t; -*-
|
||||
;;; feature/debug/packages.el
|
||||
;;; feature/debugger/packages.el
|
||||
|
||||
(package! realgud)
|
@ -1,13 +1,12 @@
|
||||
#+TITLE: :feature eval
|
||||
|
||||
This modules adds support for REPLs, build tasks and code evaluation.
|
||||
This modules adds support for evaluating code from inside Emacs. This includes REPLs and direct access to the interpreters and compilers of many languages.
|
||||
|
||||
* Table of Contents :TOC:
|
||||
- [[#install][Install]]
|
||||
- [[#usage][Usage]]
|
||||
- [[#configuration][Configuration]]
|
||||
- [[#repls][REPLs]]
|
||||
- [[#build-tasks][Build Tasks]]
|
||||
- [[#code-evaluation][Code Evaluation]]
|
||||
|
||||
* Install
|
||||
@ -20,15 +19,8 @@ Check the README.org in that language's module for details.
|
||||
Invoked via:
|
||||
+ ~:repl~ (evil ex-command)
|
||||
+ =<leader> o r= in normal mode (or visual mode, which sends the selection to the open REPL)
|
||||
+ ~M-x +eval/repl~
|
||||
+ ~M-x +eval/repl-send-region~ while a selection (and REPL) is active
|
||||
|
||||
+ *Build Tasks*
|
||||
You will be prompted to select a task. Only the ones that meet the predicate will be listed.
|
||||
+ ~:build~ (evil ex-command)
|
||||
+ =M-b= (by default)
|
||||
+ =<leader> o b= in normal mode
|
||||
+ ~M-x +eval/build~
|
||||
+ ~M-x +eval/open-repl~
|
||||
+ ~M-x +eval/send-region-to-repl~ while a selection (and REPL) is active
|
||||
|
||||
+ *Code Evaluation*
|
||||
Quickrun can be invoked via:
|
||||
@ -60,35 +52,6 @@ FUNCTION must return the repl buffer. Any window changes are ignored, then hande
|
||||
(set! :repl 'emacs-lisp-mode #'+emacs-lisp/repl)
|
||||
#+END_SRC
|
||||
|
||||
** Build Tasks
|
||||
A build task is little more than a major-mode-local interactive command that performs a task, such as compiling the current project or running unit tests. A predicate function can be supplied to ensure a command is only available when it is appropriate.
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun +lua/run-love ()
|
||||
"Run the current project in love 10.0."
|
||||
(async-shell-command
|
||||
(format "/usr/bin/love %s"
|
||||
(shell-quote-argument (doom-project-root)))))
|
||||
|
||||
(defun +lua/build ()
|
||||
"Run a build script in the project root."
|
||||
(let ((default-directory (doom-project-root)))
|
||||
(compile "luajit build.lua")))
|
||||
|
||||
(defun +lua/generate-docs ()
|
||||
"Generate project documentation."
|
||||
(let ((default-directory (doom-project-root)))
|
||||
(compile "luadoc *.lua")))
|
||||
|
||||
(defun +lua-love-p ()
|
||||
"Returns non-nil if the current project is a love project."
|
||||
(doom-project-has! (and "main.lua" "config.lua")))
|
||||
|
||||
(set! :build 'run 'lua-mode #'+lua/run-love :when (+lua-love-p))
|
||||
(set! :build 'build-project 'lua-mode #'+lua/build :when (+lua-love-p))
|
||||
(set! :build 'generate-docs 'lua-mode #'+lua/generate-docs)
|
||||
#+END_SRC
|
||||
|
||||
** Code Evaluation
|
||||
Run regions or entire buffers with [[https://github.com/syohex/emacs-quickrun][Quickrun]]. Output will be sent to a popup window.
|
||||
|
||||
|
@ -1,45 +0,0 @@
|
||||
;;; feature/eval/autoload/build.el -*- lexical-binding: t; -*-
|
||||
|
||||
(defvar-local +eval-last-builder nil
|
||||
"The last builder run in the current buffer.")
|
||||
|
||||
(defvar +eval-current-builder nil
|
||||
"The spec for the currently running builder. Available from inside builder
|
||||
functions.")
|
||||
|
||||
(defun +eval--read-builder ()
|
||||
(when-let (builders
|
||||
(cl-remove-if-not
|
||||
(lambda (plist)
|
||||
(if-let (pred (plist-get plist :when))
|
||||
(and (or (symbolp pred)
|
||||
(functionp pred))
|
||||
(funcall pred))
|
||||
t))
|
||||
(cl-delete-duplicates
|
||||
(reverse (cdr (assq major-mode +eval-builders)))
|
||||
:key 'car)
|
||||
:key 'cdr))
|
||||
(if (= (length builders) 1)
|
||||
(car builders)
|
||||
(when-let (builder (completing-read "Build: " (mapcar #'car builders) nil t))
|
||||
(assq (intern builder) builders)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +eval/build (builder)
|
||||
"TODO"
|
||||
(interactive
|
||||
(list (or +eval-last-builder
|
||||
(+eval--read-builder)
|
||||
(error "No builder for this buffer"))))
|
||||
(unless builder
|
||||
(error "Builder not found in registered builders"))
|
||||
(let ((name (car builder))
|
||||
(fn (plist-get (cdr builder) :fn)))
|
||||
(message "Running %s" name)
|
||||
(if (or (functionp fn)
|
||||
(and (symbolp fn) (fboundp fn)))
|
||||
(let ((+eval-current-builder builder))
|
||||
(funcall fn))
|
||||
(error "'%s' builder is invalid" name))))
|
||||
|
@ -4,22 +4,22 @@
|
||||
(defun +eval/buffer ()
|
||||
"Evaluate the whole buffer."
|
||||
(interactive)
|
||||
(cond ((assq major-mode +eval-runners-alist)
|
||||
(cond ((assq major-mode +eval-runners)
|
||||
(+eval/region (point-min) (point-max)))
|
||||
(t (quickrun))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +eval/region (beg end)
|
||||
"Evaluate a region and, if large enough, prints its output to a popup buffer (if an
|
||||
elisp buffer). Otherwise forward the region to Quickrun."
|
||||
"Evaluate a region between BEG and END and display the output."
|
||||
(interactive "r")
|
||||
(let ((load-file-name buffer-file-name))
|
||||
(if-let (runner (cdr (assq major-mode +eval-runners-alist)))
|
||||
(if-let (runner (cdr (assq major-mode +eval-runners)))
|
||||
(funcall runner beg end)
|
||||
(quickrun-region beg end))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +eval/region-and-replace (beg end)
|
||||
"Evaluation a region between BEG and END, and replace it with the result."
|
||||
(interactive "r")
|
||||
(cond ((eq major-mode 'emacs-lisp-mode)
|
||||
(kill-region beg end)
|
||||
|
@ -18,5 +18,5 @@
|
||||
:move-point nil
|
||||
(interactive "<r><!>")
|
||||
(if (evil-normal-state-p)
|
||||
(+eval/repl)
|
||||
(+eval/repl-send-region beg end bang)))
|
||||
(+eval/open-repl)
|
||||
(+eval/send-region-to-repl beg end bang)))
|
||||
|
@ -25,7 +25,7 @@
|
||||
t))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +eval/repl ()
|
||||
(defun +eval/open-repl ()
|
||||
"Opens (or reopens) the REPL associated with the current major-mode and place
|
||||
the cursor at the prompt."
|
||||
(interactive)
|
||||
@ -36,7 +36,7 @@ the cursor at the prompt."
|
||||
t)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +eval/repl-send-region (beg end &optional auto-execute-p)
|
||||
(defun +eval/send-region-to-repl (beg end &optional auto-execute-p)
|
||||
"REPL must be open! Sends a selected region to it. If AUTO-EXECUTE-P, then
|
||||
execute it immediately after."
|
||||
(interactive "r")
|
||||
|
@ -1,39 +1,15 @@
|
||||
;;; feature/eval/config.el -*- lexical-binding: t; -*-
|
||||
|
||||
;;
|
||||
;; Code building
|
||||
;;
|
||||
|
||||
(defvar +eval-builders nil
|
||||
"A nested alist, mapping major modes to build function plists. Used by
|
||||
`+eval/build' and filled with the `:build' setting.")
|
||||
|
||||
(def-setting! :build (name modes fn &rest plist)
|
||||
"Define a build function (FN) for MODES (can be major or minor) called NAME.
|
||||
|
||||
PLIST accepts the following properties:
|
||||
|
||||
:when FORM A predicate to determine if the builder is appropriate for this
|
||||
buffer."
|
||||
`(dolist (mode ',(doom-enlist (doom-unquote modes)) +eval-builders)
|
||||
(unless (assq mode +eval-builders)
|
||||
(push (list mode) +eval-builders))
|
||||
(cl-pushnew (cons ,name (append (list :fn ,fn) (list ,@plist)))
|
||||
(cdr (assq mode +eval-builders))
|
||||
:test #'eq :key #'car)))
|
||||
|
||||
|
||||
;;
|
||||
;; REPLs
|
||||
;;
|
||||
|
||||
(defvar +eval-repls nil
|
||||
"An alist mapping major modes to plists that describe REPLs. Used by
|
||||
`+eval/repl' and filled with the `:repl' setting.")
|
||||
`+eval/open-repl' and filled with the `:repl' setting.")
|
||||
|
||||
(define-minor-mode +eval-repl-mode
|
||||
"A minor mode for REPL buffers."
|
||||
:init-value nil)
|
||||
"A minor mode for REPL buffers.")
|
||||
|
||||
(def-setting! :repl (mode command)
|
||||
"Define a REPL for a mode. MODE is a major mode symbol and COMMAND is a
|
||||
@ -53,7 +29,7 @@ function that creates and returns the REPL buffer."
|
||||
(setq eval-expression-print-length nil
|
||||
eval-expression-print-level nil)
|
||||
|
||||
(defvar +eval-runners-alist nil
|
||||
(defvar +eval-runners nil
|
||||
"Alist mapping major modes to interactive runner functions.")
|
||||
|
||||
(def-setting! :eval (mode command)
|
||||
@ -67,10 +43,10 @@ function that creates and returns the REPL buffer."
|
||||
3. If MODE is not a string and COMMAND is an alist, see `quickrun-add-command':
|
||||
(quickrun-add-command MODE COMMAND :mode MODE).
|
||||
4. If MODE is not a string and COMMANd is a symbol, add it to
|
||||
`+eval-runners-alist', which is used by `+eval/region'."
|
||||
`+eval-runners', which is used by `+eval/region'."
|
||||
(let ((command (doom-unquote command)))
|
||||
(cond ((symbolp command)
|
||||
`(push (cons ,mode ',command) +eval-runners-alist))
|
||||
`(push (cons ,mode ',command) +eval-runners))
|
||||
((stringp command)
|
||||
`(after! quickrun
|
||||
(push (cons ,mode ',command)
|
||||
@ -91,12 +67,10 @@ function that creates and returns the REPL buffer."
|
||||
quickrun-compile-only
|
||||
quickrun-replace-region)
|
||||
:init
|
||||
(add-hook 'quickrun--mode-hook #'nlinum-mode)
|
||||
(unless (boundp 'display-line-numbers)
|
||||
(add-hook 'quickrun--mode-hook #'nlinum-mode))
|
||||
:config
|
||||
(set! :popup
|
||||
'("*quickrun*" :size 10 :noesc t :autokill t :autoclose t)
|
||||
'("*eval*" :size 12 :noselect t :autokill t :autoclose t)
|
||||
'("*Pp Eval Output*" :size 12 :noselect t :autokill t :autoclose t))
|
||||
(set! :popup "*quickrun*" :size 6 :autokill t :autoclose t)
|
||||
|
||||
(defun +eval*quickrun-auto-close (&rest _)
|
||||
"Allows us to silently re-run quickrun from within the quickrun buffer."
|
||||
@ -111,6 +85,7 @@ function that creates and returns the REPL buffer."
|
||||
(defun +eval|quickrun-scroll-to-bof ()
|
||||
"Ensures window is scrolled to BOF on invocation."
|
||||
(with-selected-window (get-buffer-window quickrun--buffer-name)
|
||||
(goto-char (point-min))))
|
||||
(goto-char (point-min))
|
||||
(doom-popup-fit-to-buffer)))
|
||||
(add-hook 'quickrun-after-run-hook #'+eval|quickrun-scroll-to-bof))
|
||||
|
||||
|
@ -26,81 +26,13 @@
|
||||
(save-excursion (goto-char beg) (point-marker))
|
||||
end)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +evil*ex-replace-special-filenames (file-name)
|
||||
"Replace special symbols in FILE-NAME. Modified to include other substitution
|
||||
flags. See http://vimdoc.sourceforge.net/htmldoc/cmdline.html#filename-modifiers."
|
||||
(let* (case-fold-search
|
||||
(regexp (concat "\\(?:^\\|[^\\\\]\\)"
|
||||
"\\([#%]\\)"
|
||||
"\\(\\(?::\\(?:[PphtreS~.]\\|g?s[^:\t\n ]+\\)\\)*\\)"))
|
||||
(matches
|
||||
(cl-loop with i = 0
|
||||
while (and (< i (length file-name))
|
||||
(string-match regexp file-name i))
|
||||
do (setq i (1+ (match-beginning 0)))
|
||||
and collect
|
||||
(cl-loop for j to (/ (length (match-data)) 2)
|
||||
collect (match-string j file-name)))))
|
||||
(dolist (match matches)
|
||||
(let ((flags (split-string (car (cdr (cdr match))) ":" t))
|
||||
(path (and buffer-file-name
|
||||
(pcase (car (cdr match))
|
||||
("%" (file-relative-name buffer-file-name))
|
||||
("#" (save-excursion (other-window 1) (file-relative-name buffer-file-name))))))
|
||||
flag global)
|
||||
(if (not path)
|
||||
(setq path "")
|
||||
(while flags
|
||||
(setq flag (pop flags))
|
||||
(when (string-suffix-p "\\" flag)
|
||||
(setq flag (concat flag (pop flags))))
|
||||
(when (string-prefix-p "gs" flag)
|
||||
(setq global t
|
||||
flag (substring flag 1)))
|
||||
(setq path
|
||||
(or (pcase (substring flag 0 1)
|
||||
("p" (expand-file-name path))
|
||||
("~" (concat "~/" (file-relative-name path "~")))
|
||||
("." (file-relative-name path default-directory))
|
||||
("t" (file-name-nondirectory (directory-file-name path)))
|
||||
("r" (file-name-sans-extension path))
|
||||
("e" (file-name-extension path))
|
||||
("S" (shell-quote-argument path))
|
||||
("h"
|
||||
(let ((parent (file-name-directory (expand-file-name path))))
|
||||
(unless (equal (file-truename path)
|
||||
(file-truename parent))
|
||||
(if (file-name-absolute-p path)
|
||||
(directory-file-name parent)
|
||||
(file-relative-name parent)))))
|
||||
("s"
|
||||
(when-let (args (evil-delimited-arguments (substring flag 1) 2))
|
||||
(let ((pattern (evil-transform-vim-style-regexp (car args)))
|
||||
(replace (cadr args)))
|
||||
(replace-regexp-in-string
|
||||
(if global pattern (concat "\\(" pattern "\\).*\\'"))
|
||||
(evil-transform-vim-style-regexp replace) path t t
|
||||
(unless global 1)))))
|
||||
("P"
|
||||
(let ((default-directory (file-name-directory (expand-file-name path))))
|
||||
(abbreviate-file-name (doom-project-root))))
|
||||
(_ path))
|
||||
"")))
|
||||
;; strip trailing slash, if applicable
|
||||
(when (and (not (string= path "")) (equal (substring path -1) "/"))
|
||||
(setq path (substring path 0 -1))))
|
||||
(setq file-name
|
||||
(replace-regexp-in-string (format "\\(?:^\\|[^\\\\]\\)\\(%s\\)"
|
||||
(regexp-quote (string-trim-left (car match))))
|
||||
path file-name t t 1))))
|
||||
(setq file-name (replace-regexp-in-string regexp "\\1" file-name t))))
|
||||
|
||||
(defun +evil--window-swap (direction)
|
||||
"Move current window to the next window in DIRECTION. If there are no windows
|
||||
there and there is only one window, split in that direction and place this
|
||||
window there. If there are no windows and this isn't the only window, use
|
||||
evil-window-move-* (e.g. `evil-window-move-far-left')"
|
||||
(when (doom-popup-p)
|
||||
(doom/popup-raise))
|
||||
(let* ((this-window (get-buffer-window))
|
||||
(this-buffer (current-buffer))
|
||||
(that-window (windmove-find-other-window direction nil this-window))
|
||||
|
@ -92,7 +92,7 @@
|
||||
;; --- evil hacks -------------------------
|
||||
(defvar +evil-esc-hook '(t)
|
||||
"A hook run after ESC is pressed in normal mode (invoked by
|
||||
`evil-force-normal-state'). If a hook returns non-nil, all hooks after it are
|
||||
`evil-force-normal-state'). If any hook returns non-nil, all hooks after it are
|
||||
ignored.")
|
||||
|
||||
(defun +evil*attach-escape-hook ()
|
||||
@ -124,8 +124,7 @@ across windows."
|
||||
|
||||
;; monkey patch `evil-ex-replace-special-filenames' to add more ex
|
||||
;; substitution flags to evil-mode
|
||||
(advice-add #'evil-ex-replace-special-filenames
|
||||
:override #'+evil*ex-replace-special-filenames)
|
||||
(advice-add #'evil-ex-replace-special-filenames :override #'doom-resolve-vim-path)
|
||||
|
||||
;; These arg types will highlight matches in the current buffer
|
||||
(evil-ex-define-argument-type buffer-match :runner +evil-ex-buffer-match)
|
||||
@ -144,6 +143,8 @@ across windows."
|
||||
(evil-define-interactive-code "<//g>"
|
||||
:ex-arg global-match (list (when (evil-ex-p) evil-ex-argument)))
|
||||
|
||||
;; Forward declare these so that ex completion works, even if the autoloaded
|
||||
;; functions aren't loaded yet.
|
||||
(evil-set-command-properties
|
||||
'+evil:align :move-point t :ex-arg 'buffer-match :ex-bang t :evil-mc t :keep-visual t :suppress-operator t)
|
||||
(evil-set-command-properties
|
||||
@ -282,7 +283,7 @@ the new algorithm is confusing, like in python or ruby."
|
||||
:commands (evil-mc-make-cursor-here evil-mc-make-all-cursors
|
||||
evil-mc-undo-all-cursors evil-mc-pause-cursors
|
||||
evil-mc-resume-cursors evil-mc-make-and-goto-first-cursor
|
||||
evil-mc-make-and-goto-last-cursor evil-mc-make-cursor-here
|
||||
evil-mc-make-and-goto-last-cursor
|
||||
evil-mc-make-cursor-move-next-line
|
||||
evil-mc-make-cursor-move-prev-line evil-mc-make-cursor-at-pos
|
||||
evil-mc-has-cursors-p evil-mc-make-and-goto-next-cursor
|
||||
@ -382,3 +383,64 @@ the new algorithm is confusing, like in python or ruby."
|
||||
|
||||
(def-package! evil-textobj-anyblock
|
||||
:commands (evil-textobj-anyblock-inner-block evil-textobj-anyblock-a-block))
|
||||
|
||||
|
||||
;;
|
||||
;; Multiple cursors compatibility (for the plugins that use it)
|
||||
;;
|
||||
|
||||
;; mc doesn't play well with evil, this attempts to assuage some of its problems
|
||||
;; so that certain plugins (which I have no control over) can still use it in
|
||||
;; relative safety.
|
||||
(after! multiple-cursors-core
|
||||
(map! :map mc/keymap :ne "<escape>" #'mc/keyboard-quit)
|
||||
|
||||
(defvar +evil--mc-compat-evil-prev-state nil)
|
||||
(defvar +evil--mc-compat-mark-was-active nil)
|
||||
|
||||
(defsubst +evil--visual-or-normal-p ()
|
||||
"True if evil mode is enabled, and we are in normal or visual mode."
|
||||
(and (bound-and-true-p evil-mode)
|
||||
(not (memq evil-state '(insert emacs)))))
|
||||
|
||||
(defun +evil|mc-compat-switch-to-emacs-state ()
|
||||
(when (+evil--visual-or-normal-p)
|
||||
(setq +evil--mc-compat-evil-prev-state evil-state)
|
||||
(when (region-active-p)
|
||||
(setq +evil--mc-compat-mark-was-active t))
|
||||
(let ((mark-before (mark))
|
||||
(point-before (point)))
|
||||
(evil-emacs-state 1)
|
||||
(when (or +evil--mc-compat-mark-was-active (region-active-p))
|
||||
(goto-char point-before)
|
||||
(set-mark mark-before)))))
|
||||
|
||||
(defun +evil|mc-compat-back-to-previous-state ()
|
||||
(when +evil--mc-compat-evil-prev-state
|
||||
(unwind-protect
|
||||
(case +evil--mc-compat-evil-prev-state
|
||||
((normal visual) (evil-force-normal-state))
|
||||
(t (message "Don't know how to handle previous state: %S"
|
||||
+evil--mc-compat-evil-prev-state)))
|
||||
(setq +evil--mc-compat-evil-prev-state nil)
|
||||
(setq +evil--mc-compat-mark-was-active nil))))
|
||||
|
||||
(add-hook 'multiple-cursors-mode-enabled-hook '+evil|mc-compat-switch-to-emacs-state)
|
||||
(add-hook 'multiple-cursors-mode-disabled-hook '+evil|mc-compat-back-to-previous-state)
|
||||
|
||||
(defun +evil|mc-evil-compat-rect-switch-state ()
|
||||
(if rectangular-region-mode
|
||||
(+evil|mc-compat-switch-to-emacs-state)
|
||||
(setq +evil--mc-compat-evil-prev-state nil)))
|
||||
|
||||
;; When running edit-lines, point will return (position + 1) as a
|
||||
;; result of how evil deals with regions
|
||||
(defadvice mc/edit-lines (before change-point-by-1 activate)
|
||||
(when (+evil--visual-or-normal-p)
|
||||
(if (> (point) (mark))
|
||||
(goto-char (1- (point)))
|
||||
(push-mark (1- (mark))))))
|
||||
|
||||
(add-hook 'rectangular-region-mode-hook '+evil|mc-evil-compat-rect-switch-state)
|
||||
|
||||
(defvar mc--default-cmds-to-run-once nil))
|
||||
|
@ -3,52 +3,19 @@
|
||||
|
||||
(require! :feature evil)
|
||||
|
||||
;; `+evil*ex-replace-special-filenames'
|
||||
;; `evil-ex-replace-special-filenames'
|
||||
;; NOTE The majority of this function is tested in core/test/core-lib.el, this
|
||||
;; only tests the evil-mode-specific functionality.
|
||||
(def-test! file-modifiers
|
||||
(cl-flet ((do-it #'+evil*ex-replace-special-filenames))
|
||||
(cl-flet ((do-it #'evil-ex-replace-special-filenames))
|
||||
(let ((buffer-file-name "~/.emacs.d/test/modules/feature/test-evil.el")
|
||||
(default-directory "~/.emacs.d/test/modules/"))
|
||||
(should (equal (do-it "%") "feature/test-evil.el"))
|
||||
(should (equal (do-it "%:r") "feature/test-evil"))
|
||||
(should (equal (do-it "%:r.elc") "feature/test-evil.elc"))
|
||||
(should (equal (do-it "%:e") "el"))
|
||||
(should (equal (do-it "%:p") (expand-file-name buffer-file-name)))
|
||||
(should (equal (do-it "%:h") "feature"))
|
||||
(should (equal (do-it "%:t") "test-evil.el"))
|
||||
(should (equal (do-it "%:.") "feature/test-evil.el"))
|
||||
(should (equal (do-it "%:~") "~/.emacs.d/test/modules/feature/test-evil.el"))
|
||||
(should (equal (do-it "%:s?e?x?") "fxature/test-evil.el"))
|
||||
(should (equal (do-it "%:gs?e?x?") "fxaturx/txst-xvil.xl"))
|
||||
(should (equal (file-truename (do-it "%:p"))
|
||||
(file-truename buffer-file-name))))))
|
||||
|
||||
(def-test! nested-file-modifiers
|
||||
(cl-flet ((do-it #'+evil*ex-replace-special-filenames))
|
||||
(let ((buffer-file-name "~/vim/src/version.c")
|
||||
(default-directory "~/vim/"))
|
||||
(should (equal (do-it "%:p") (expand-file-name "~/vim/src/version.c")))
|
||||
(should (equal (do-it "%:p:.") "src/version.c"))
|
||||
(should (equal (do-it "%:p:~") "~/vim/src/version.c"))
|
||||
(should (equal (do-it "%:h") "src"))
|
||||
(should (equal (do-it "%:p:h") (expand-file-name "~/vim/src")))
|
||||
(should (equal (do-it "%:p:h:h") (expand-file-name "~/vim")))
|
||||
(should (equal (do-it "%:t") "version.c"))
|
||||
(should (equal (do-it "%:p:t") "version.c"))
|
||||
(should (equal (do-it "%:r") "src/version"))
|
||||
(should (equal (do-it "%:p:r") (expand-file-name "~/vim/src/version")))
|
||||
(should (equal (do-it "%:t:r") "version")))))
|
||||
(should (equal (do-it "%:gs?e?x?") "fxaturx/txst-xvil.xl")))))
|
||||
|
||||
(def-test! empty-file-modifiers
|
||||
(cl-flet ((do-it #'+evil*ex-replace-special-filenames))
|
||||
(cl-flet ((do-it #'evil-ex-replace-special-filenames))
|
||||
(let (buffer-file-name default-directory)
|
||||
(should (equal (do-it "%") ""))
|
||||
(should (equal (do-it "%:r") ""))
|
||||
(should (equal (do-it "%:e") ""))
|
||||
(should (equal (do-it "%:h") ""))
|
||||
(should (equal (do-it "%:t") ""))
|
||||
(should (equal (do-it "%:.") ""))
|
||||
(should (equal (do-it "%:~") ""))
|
||||
(should (equal (do-it "%:s?e?x?") ""))
|
||||
(should (equal (do-it "%:gs?e?x?") ""))
|
||||
(should (equal (do-it "%:P") "")))))
|
||||
(should (equal (do-it "%:gs?e?x?") "")))))
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
(defvar +file-templates-dir
|
||||
(expand-file-name "templates/" (file-name-directory load-file-name))
|
||||
"")
|
||||
"The path to a directory of yasnippet folders to use for file templates.")
|
||||
|
||||
(def-package! autoinsert ; built-in
|
||||
:defer 1
|
||||
@ -12,12 +12,12 @@
|
||||
(setq auto-insert-query nil ; Don't prompt before insertion
|
||||
auto-insert-alist nil) ; Tabula rasa
|
||||
|
||||
(after! yasnippet
|
||||
(push '+file-templates-dir yas-snippet-dirs))
|
||||
|
||||
:config
|
||||
(auto-insert-mode 1)
|
||||
|
||||
(after! yasnippet
|
||||
(push '+file-templates-dir yas-snippet-dirs))
|
||||
|
||||
(defun +file-templates--expand (key &optional mode project-only)
|
||||
"Auto insert a snippet of yasnippet into new file."
|
||||
(when (if project-only (doom-project-p) t)
|
||||
@ -55,6 +55,7 @@
|
||||
("-test\\.el$" "__" emacs-ert-mode)
|
||||
("/.emacs.d/.+\\.el$" "__doom-module" emacs-lisp-mode)
|
||||
("/.emacs.d/.+/packages\\.el$" "__doom-packages" emacs-lisp-mode)
|
||||
("/.emacs.d/.+/test\\.el$" "__doom-test" emacs-lisp-mode)
|
||||
("/.emacs.d/.+/README\\.org$" "__doom-readme" org-mode)
|
||||
(snippet-mode "__" snippet-mode)
|
||||
;; Go
|
||||
@ -72,8 +73,6 @@
|
||||
("/bower\\.json$" "__bower.json" json-mode)
|
||||
("/gulpfile\\.js$" "__gulpfile.js" js-mode)
|
||||
("/webpack\\.config\\.js$" "__webpack.config.js" js-mode)
|
||||
("\\.lbaction/.+/Info.plist$" "__Info.plst" lb6-mode)
|
||||
("\\.lbaction/.+/\\(default\\|suggestions\\)\\.js$" "__default.js" lb6-mode)
|
||||
;; Lua
|
||||
("/main\\.lua$" "__main.lua" love-mode)
|
||||
("/conf\\.lua$" "__conf.lua" love-mode)
|
||||
@ -107,5 +106,6 @@
|
||||
;; Slim
|
||||
("/\\(index\\|main\\)\\.slim$" "__" slim-mode)
|
||||
;; Shell scripts
|
||||
("\\.z?sh$" "__" sh-mode))))
|
||||
("\\.z?sh$" "__" sh-mode)
|
||||
("\\.zunit$" "__zunit" sh-mode))))
|
||||
|
||||
|
@ -0,0 +1,4 @@
|
||||
;; -*- no-byte-compile: t; -*-
|
||||
;;; `(file-relative-name buffer-file-name doom-modules-dir)`
|
||||
|
||||
$0
|
@ -1,99 +0,0 @@
|
||||
# -*- mode: snippet -*-
|
||||
# name: Info.plist File Template
|
||||
# condition: (eq major-mode 'nxml-mode)
|
||||
# --
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>io.henrik.launchbar.${1:$(replace-regexp-in-string "[^a-zA-Z0-9]" "" yas-text)}</string>
|
||||
|
||||
<key>CFBundleName</key>
|
||||
<string>${1:Action Name}</string>
|
||||
|
||||
<!-- <key>CFBundleShortVersionString</key> -->
|
||||
<!-- <value>1.0</value> -->
|
||||
|
||||
<key>CFBundleVersion</key>
|
||||
<string>${2:1.0.0}</string>
|
||||
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>icon</string>
|
||||
|
||||
<key>LBDebugLogEnabled</key>
|
||||
<false />
|
||||
|
||||
<!-- LB stuff -->
|
||||
<!-- <key>LSMinimumSystemVersion</key> -->
|
||||
<!-- <string>10.9.1</string> -->
|
||||
|
||||
<!-- Per-action keys -->
|
||||
<!-- <key>LBTextInputTitle</key> -->
|
||||
<!-- <string>Rate</string> -->
|
||||
|
||||
<key>LBScripts</key>
|
||||
<dict>
|
||||
<key>LBDefaultScript</key>
|
||||
<dict>
|
||||
<key>LBScriptName</key>
|
||||
<string>default.js</string>
|
||||
|
||||
<key>LBRunInBackground</key>
|
||||
<false />
|
||||
|
||||
<key>LBRequiresArgument</key>
|
||||
<true />
|
||||
|
||||
<key>LBAcceptedArgumentTypes</key>
|
||||
<array>
|
||||
<string>string</string>
|
||||
</array>
|
||||
|
||||
<key>LBReturnsResult</key>
|
||||
<true />
|
||||
|
||||
<key>LBReturnType</key>
|
||||
<string>string</string>
|
||||
</dict>
|
||||
</dict>
|
||||
|
||||
<key>LBDescription</key>
|
||||
<dict>
|
||||
<key>LBAuthor</key>
|
||||
<string>Henrik Lissner</string>
|
||||
|
||||
<key>LBWebsite</key>
|
||||
<string>http://v0.io/launchbar</string>
|
||||
|
||||
<key>LBEmail</key>
|
||||
<string>contact@henrik.io</string>
|
||||
|
||||
<key>LBTwitter</key>
|
||||
<string>@vnought</string>
|
||||
|
||||
<key>LBSummary</key>
|
||||
<string>${3:A short summary of this action}</string>
|
||||
|
||||
<key>LBArgument</key>
|
||||
<string>${4:Describe the input(s) for this action}</string>${5:
|
||||
|
||||
<key>LBResult</key>
|
||||
<string>${6:Describe the result type}</string>
|
||||
|
||||
}${7:<key>LBRequirements</key>
|
||||
<string>${8:The requirements for this action to work}</string>}
|
||||
|
||||
<!-- <key>LBChangelog</key> -->
|
||||
<!-- <string></string> -->
|
||||
|
||||
<key>LBUpdateURL</key>
|
||||
<string>https://github.com/hlissner/lb6-${2:actions}/blob/master/$1.lbaction/Contents/Info.plist</string>
|
||||
|
||||
<key>LBDownloadURL</key>
|
||||
<string>https://dl.v0.io/launchbar/$1.lbaction</string>
|
||||
</dict>
|
||||
|
||||
</dict>
|
||||
</plist>
|
@ -1,40 +0,0 @@
|
||||
# -*- mode: snippet -*-
|
||||
# name: default.js file template
|
||||
# condition: (memq major-mode '(js-mode js2-mode))
|
||||
# --
|
||||
/*global Lib*/
|
||||
|
||||
${1:include("shared/${2:lib.js}");
|
||||
|
||||
}// This function is called when the user runs the action without any argument,
|
||||
// e.g. by selecting it and hitting enter, space or the right arrow key
|
||||
// (assuming the action does not specify that it requires an argument in its
|
||||
// Info.plist). run is also called as a fallback if the more specific runWith...
|
||||
// function for a given argument type (see below) is not implemented.
|
||||
function run() {
|
||||
$0
|
||||
}
|
||||
|
||||
// This function is called after text input or when the user sends text to the
|
||||
// action using Send To.
|
||||
function runWithString(string) {
|
||||
|
||||
}
|
||||
|
||||
// This function is called when a URL item is sent to the action. This is also
|
||||
// the case when a Action URL is called.
|
||||
function runWithURL(url, details) {
|
||||
|
||||
}
|
||||
|
||||
// This function is called when the user sends a result item of a previous
|
||||
// action run to the action using Send To.
|
||||
function runWithItem(item) {
|
||||
|
||||
}
|
||||
|
||||
// This function is called after showing a file open dialog or when the user
|
||||
// sends one or more files or folders to the action using Send To.
|
||||
function runWithPaths(paths) {
|
||||
|
||||
}
|
5
modules/feature/file-templates/templates/sh-mode/__zunit
Normal file
5
modules/feature/file-templates/templates/sh-mode/__zunit
Normal file
@ -0,0 +1,5 @@
|
||||
#!/usr/bin/env zunit
|
||||
|
||||
@test '...' {
|
||||
$0
|
||||
}
|
@ -1,2 +0,0 @@
|
||||
;;; feature/hydra/autoload/evil.el -*- lexical-binding: t; -*-
|
||||
|
@ -1,2 +0,0 @@
|
||||
;;; feature/hydra/autoload/hydras.el -*- lexical-binding: t; -*-
|
||||
|
@ -1,97 +0,0 @@
|
||||
;;; feature/hydra/config.el -*- lexical-binding: t; -*-
|
||||
|
||||
(def-package! hydra
|
||||
:commands (+hydra-zoom/body +hydra-window/body defhydra)
|
||||
:config
|
||||
(setq lv-use-separator t)
|
||||
|
||||
(defhydra +hydra-zoom (:hint t :color red)
|
||||
"zoom"
|
||||
("j" text-scale-increase "in")
|
||||
("k" text-scale-decrease "out")
|
||||
("0" (text-scale-set 0) "reset"))
|
||||
|
||||
(defhydra +hydra-window (:hint nil)
|
||||
"
|
||||
Split: _v_ert _s_:horz
|
||||
Delete: _c_lose _o_nly
|
||||
Switch Window: _h_:left _j_:down _k_:up _l_:right
|
||||
Buffers: _p_revious _n_ext _b_:select _f_ind-file
|
||||
Resize: _H_:splitter left _J_:splitter down _K_:splitter up _L_:splitter right
|
||||
Move: _a_:up _z_:down _i_menu"
|
||||
|
||||
|
||||
("z" scroll-up-line)
|
||||
("a" scroll-down-line)
|
||||
("i" idomenu)
|
||||
|
||||
("h" windmove-left)
|
||||
("j" windmove-down)
|
||||
("k" windmove-up)
|
||||
("l" windmove-right)
|
||||
|
||||
("p" previous-buffer)
|
||||
("n" next-buffer)
|
||||
("b" ido-switch-buffer)
|
||||
("f" ido-find-file)
|
||||
|
||||
("s" split-window-below)
|
||||
("v" split-window-right)
|
||||
|
||||
("c" delete-window)
|
||||
("o" delete-other-windows)
|
||||
|
||||
("H" hydra-move-splitter-left)
|
||||
("J" hydra-move-splitter-down)
|
||||
("K" hydra-move-splitter-up)
|
||||
("L" hydra-move-splitter-right)
|
||||
|
||||
("q" nil)))
|
||||
|
||||
|
||||
(def-package! ivy-hydra
|
||||
:when (featurep! :completion ivy)
|
||||
:after hydra
|
||||
:config
|
||||
(define-key ivy-mode-map (kbd "C-o")
|
||||
(defhydra coo-ivy (:hint nil :color pink)
|
||||
"
|
||||
Move ^^^^^^^^^^ | Call ^^^^ | Cancel^^ | Options^^ | Action _w_/_s_/_a_: %s(ivy-action-name)
|
||||
----------^^^^^^^^^^-+--------------^^^^-+-------^^-+--------^^-+---------------------------------
|
||||
_g_ ^ ^ _k_ ^ ^ _u_ | _f_orward _o_ccur | _i_nsert | _c_alling: %-7s(if ivy-calling \"on\" \"off\") _C_ase-fold: %-10`ivy-case-fold-search
|
||||
^↨^ _h_ ^+^ _l_ ^↕^ | _RET_ done ^^ | _q_uit | _m_atcher: %-7s(ivy--matcher-desc) _t_runcate: %-11`truncate-lines
|
||||
_G_ ^ ^ _j_ ^ ^ _d_ | _TAB_ alt-done ^^ | ^ ^ | _<_/_>_: shrink/grow
|
||||
"
|
||||
;; arrows
|
||||
("j" ivy-next-line)
|
||||
("k" ivy-previous-line)
|
||||
("l" ivy-alt-done)
|
||||
("h" ivy-backward-delete-char)
|
||||
("g" ivy-beginning-of-buffer)
|
||||
("G" ivy-end-of-buffer)
|
||||
("d" ivy-scroll-up-command)
|
||||
("u" ivy-scroll-down-command)
|
||||
("e" ivy-scroll-down-command)
|
||||
;; actions
|
||||
("q" keyboard-escape-quit :exit t)
|
||||
("C-g" keyboard-escape-quit :exit t)
|
||||
("<escape>" keyboard-escape-quit :exit t)
|
||||
("C-o" nil)
|
||||
("i" nil)
|
||||
("TAB" ivy-alt-done :exit nil)
|
||||
("C-j" ivy-alt-done :exit nil)
|
||||
;; ("d" ivy-done :exit t)
|
||||
("RET" ivy-done :exit t)
|
||||
("C-m" ivy-done :exit t)
|
||||
("f" ivy-call)
|
||||
("c" ivy-toggle-calling)
|
||||
("m" ivy-toggle-fuzzy)
|
||||
(">" ivy-minibuffer-grow)
|
||||
("<" ivy-minibuffer-shrink)
|
||||
("w" ivy-prev-action)
|
||||
("s" ivy-next-action)
|
||||
("a" ivy-read-action)
|
||||
("t" (setq truncate-lines (not truncate-lines)))
|
||||
("C" ivy-toggle-case-fold)
|
||||
|
||||
("o" ivy-occur :exit t))))
|
@ -1,7 +0,0 @@
|
||||
;; -*- no-byte-compile: t; -*-
|
||||
;;; feature/hydra/packages.el
|
||||
|
||||
(package! hydra)
|
||||
(when (featurep! :completion ivy)
|
||||
(package! ivy-hydra))
|
||||
|
@ -130,5 +130,5 @@ for the provider."
|
||||
(when (string-empty-p search)
|
||||
(user-error "The search query is empty"))
|
||||
(setq +jump--online-last provider)
|
||||
(browse-url (format url (url-encode-url search))))
|
||||
(funcall +jump-search-browser-fn (format url (url-encode-url search))))
|
||||
('error (setq +jump--online-last nil))))
|
||||
|
@ -16,17 +16,29 @@
|
||||
|
||||
(defvar +jump-search-provider-alist
|
||||
'(("Google" . "https://google.com/search?q=%s")
|
||||
("Google images" . "https://google.com/images?q=%s")
|
||||
("Google maps" . "https://maps.google.com/maps?q=%s")
|
||||
("Project Gutenberg" . "http://www.gutenberg.org/ebooks/search/?query=%s")
|
||||
("DuckDuckGo" . "https://duckduckgo.com/?q=%s")
|
||||
("DevDocs.io" . "http://devdocs.io/#q=%s")
|
||||
("StackOverflow" . "https://stackoverflow.com/search?q=%s"))
|
||||
("StackOverflow" . "https://stackoverflow.com/search?q=%s")
|
||||
("Github" . "https://github.com/search?ref=simplesearch&q=%s")
|
||||
("Youtube" . "https://youtube.com/results?aq=f&oq=&search_query=%s")
|
||||
("Wolfram alpha" . "https://wolframalpha.com/input/?i=%s")
|
||||
("Wikipedia" . "https://wikipedia.org/search-redirect.php?language=en&go=Go&search=%s"))
|
||||
"An alist that maps online resources to their search url or a function that
|
||||
produces an url. Used by `+jump/online'.")
|
||||
|
||||
(defconst +jump-search-browser-fn #'browse-url
|
||||
"Function to use to open search urls.")
|
||||
|
||||
(defvar +jump-function-alist nil
|
||||
"TODO")
|
||||
"An alist mapping major modes to jump function plists, describing what to do
|
||||
with `+jump/definition', `+jump/references' and `+jump/documentation' are
|
||||
called.")
|
||||
|
||||
(defvar-local +jump-current-functions nil
|
||||
"TODO")
|
||||
"The enabled jump functions for the current buffer.")
|
||||
|
||||
(def-setting! :jump (modes &rest plist)
|
||||
"Definies a jump target for major MODES. PLIST accepts the following
|
||||
|
34
modules/feature/services/autoload.el
Normal file
34
modules/feature/services/autoload.el
Normal file
@ -0,0 +1,34 @@
|
||||
;;; feature/services/autoload.el -*- lexical-binding: t; -*-
|
||||
|
||||
;;;###autoload
|
||||
(defun +services/create ()
|
||||
"Interactively create a new prodigy service."
|
||||
(interactive)
|
||||
;; TODO
|
||||
)
|
||||
|
||||
;;;###autoload
|
||||
(defun +services/prodigy-delete (arg)
|
||||
"Delete service at point. Asks for confirmation."
|
||||
(interactive "P")
|
||||
(prodigy-with-refresh
|
||||
(-when-let (service (prodigy-service-at-pos))
|
||||
(let ((name (plist-get service :name)))
|
||||
(cond ((or arg
|
||||
(y-or-n-p (format "Delete '%s' service?" name)))
|
||||
(setq prodigy-services (delete service prodigy-services))
|
||||
(ignore-errors
|
||||
(prodigy-goto-next-line))
|
||||
(message "Successfully deleted service: %s" name))
|
||||
(t
|
||||
(message "Aborted")))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +services/cleanup ()
|
||||
"Delete all services associated with projects that don't exist."
|
||||
(interactive)
|
||||
(cl-loop for service in prodigy-services
|
||||
if (and (plist-member service :project)
|
||||
(file-directory-p (plist-get service :project)))
|
||||
collect service into services
|
||||
finally do (setq prodigy-service services)))
|
50
modules/feature/services/config.el
Normal file
50
modules/feature/services/config.el
Normal file
@ -0,0 +1,50 @@
|
||||
;;; feature/services/config.el -*- lexical-binding: t; -*-
|
||||
|
||||
(def-setting! :service (&rest plist)
|
||||
"TODO"
|
||||
`(after! prodigy
|
||||
(prodigy-define-service ,@plist)))
|
||||
|
||||
|
||||
;;
|
||||
;; Plugins
|
||||
;;
|
||||
|
||||
(def-package! prodigy
|
||||
:commands (prodigy prodigy-view-mode prodigy-add-filter)
|
||||
:config
|
||||
(set! :evil-state 'prodigy-mode 'emacs)
|
||||
|
||||
;; Make services, etc persistent between Emacs sessions
|
||||
(setq prodigy-services (persistent-soft-fetch 'prodigy-services "prodigy")
|
||||
prodigy-tags (persistent-soft-fetch 'prodigy-tags "prodigy")
|
||||
prodigy-filters (persistent-soft-fetch 'prodigy-filters "prodigy"))
|
||||
|
||||
(defun +services|save ()
|
||||
"Save all services, tags and filters to files."
|
||||
(+services/cleanup)
|
||||
(cl-loop for sym in '(prodigy-services prodigy-tags prodigy-filters)
|
||||
do (persistent-soft-store sym (symbol-value sym) "prodigy")))
|
||||
(add-hook 'kill-emacs-hook #'+services|save)
|
||||
|
||||
(defun +services*prodigy-services (orig-fn &rest args)
|
||||
"Adds a new :project property to prodigy services, which hides the service
|
||||
unless invoked from the relevant project."
|
||||
(let ((project-root (downcase (doom-project-root)))
|
||||
(services (apply orig-fn args)))
|
||||
(if current-prefix-arg
|
||||
services
|
||||
(cl-remove-if-not (lambda (service)
|
||||
(let ((project (plist-get service :project)))
|
||||
(or (not project)
|
||||
(file-in-directory-p project-root project))))
|
||||
services))))
|
||||
(advice-add #'prodigy-services :around #'+services*prodigy-services)
|
||||
|
||||
;; Keybindings
|
||||
(map! :map prodigy-mode-map "d" #'+services/prodigy-delete)
|
||||
(when (featurep! :feature evil)
|
||||
(map! :map prodigy-mode-map
|
||||
"j" #'prodigy-next
|
||||
"k" #'prodigy-prev)))
|
||||
|
@ -1,4 +1,4 @@
|
||||
;; -*- no-byte-compile: t; -*-
|
||||
;;; tools/prodigy/packages.el
|
||||
;;; feature/services/packages.el
|
||||
|
||||
(package! prodigy)
|
@ -29,14 +29,11 @@
|
||||
"Refresh git-gutter on ESC. Return nil to prevent shadowing other
|
||||
`+evil-esc-hook' hooks."
|
||||
(when git-gutter-mode
|
||||
(git-gutter)
|
||||
nil))
|
||||
(ignore (git-gutter))))
|
||||
(add-hook '+evil-esc-hook #'+version-control|update-git-gutter t))
|
||||
|
||||
|
||||
(when (featurep! :feature hydra)
|
||||
(defhydra +hydra-git-gutter (:body-pre (git-gutter-mode 1)
|
||||
:hint nil)
|
||||
(def-hydra! +version-control@git-gutter
|
||||
(:body-pre (git-gutter-mode 1) :hint nil)
|
||||
"
|
||||
╭─────────────────┐
|
||||
Movement Hunk Actions Misc. │ gg: +%-4s(car (git-gutter:statistic))/ -%-3s(cdr (git-gutter:statistic)) │
|
||||
@ -47,21 +44,17 @@
|
||||
^↓ ^ [_p_] popup ╭──────────────────────
|
||||
^_j_^ │[_q_] quit
|
||||
^_G_^ │[_Q_] Quit and disable"
|
||||
("j" (progn (git-gutter:next-hunk 1)
|
||||
(recenter)))
|
||||
("k" (progn (git-gutter:previous-hunk 1)
|
||||
(recenter)))
|
||||
("g" (progn (goto-char (point-min))
|
||||
(git-gutter:next-hunk 1)))
|
||||
("G" (progn (goto-char (point-min))
|
||||
(git-gutter:previous-hunk 1)))
|
||||
("j" (progn (git-gutter:next-hunk 1) (recenter)))
|
||||
("k" (progn (git-gutter:previous-hunk 1) (recenter)))
|
||||
("g" (progn (goto-char (point-min)) (git-gutter:next-hunk 1)))
|
||||
("G" (progn (goto-char (point-min)) (git-gutter:previous-hunk 1)))
|
||||
("s" git-gutter:stage-hunk)
|
||||
("r" git-gutter:revert-hunk)
|
||||
("m" git-gutter:mark-hunk)
|
||||
("p" git-gutter:popup-hunk)
|
||||
("R" git-gutter:set-start-revision)
|
||||
("q" nil :color blue)
|
||||
("Q" (git-gutter-mode -1) :color blue))))
|
||||
("Q" (git-gutter-mode -1) :color blue)))
|
||||
|
||||
|
||||
(def-package! git-timemachine
|
||||
|
@ -1,10 +1,7 @@
|
||||
;;; feature/version-control/config.el -*- lexical-binding: t; -*-
|
||||
|
||||
(unless (featurep! -git)
|
||||
(load! +git))
|
||||
;; TODO hg support
|
||||
;; (unless (featurep! -hg)
|
||||
;; (load! +hg))
|
||||
(or (featurep! -git) (load! +git))
|
||||
;; TODO (or (featurep! -hg) (load! +hg))
|
||||
|
||||
;;
|
||||
(setq vc-make-backup-files nil)
|
||||
@ -26,17 +23,14 @@
|
||||
:init
|
||||
(add-hook 'find-file-hook #'+vcs|enable-smerge-mode-maybe)
|
||||
:config
|
||||
(when (featurep! :feature hydra)
|
||||
(require 'hydra)
|
||||
|
||||
(when (version< emacs-version "26")
|
||||
(defalias 'smerge-keep-upper 'smerge-keep-mine)
|
||||
(defalias 'smerge-keep-lower 'smerge-keep-other)
|
||||
(defalias 'smerge-diff-base-upper 'smerge-diff-base-mine)
|
||||
(defalias 'smerge-diff-upper-lower 'smerge-diff-mine-other)
|
||||
(defalias 'smerge-diff-base-lower 'smerge-diff-base-other))
|
||||
(defalias #'smerge-keep-upper #'smerge-keep-mine)
|
||||
(defalias #'smerge-keep-lower #'smerge-keep-other)
|
||||
(defalias #'smerge-diff-base-upper #'smerge-diff-base-mine)
|
||||
(defalias #'smerge-diff-upper-lower #'smerge-diff-mine-other)
|
||||
(defalias #'smerge-diff-base-lower #'smerge-diff-base-other))
|
||||
|
||||
(defhydra +hydra-smerge (:hint nil
|
||||
(def-hydra! +hydra-smerge (:hint nil
|
||||
:pre (smerge-mode 1)
|
||||
;; Disable `smerge-mode' when quitting hydra if
|
||||
;; no merge conflicts remain.
|
||||
@ -71,4 +65,4 @@
|
||||
("C" smerge-combine-with-next)
|
||||
("r" smerge-resolve)
|
||||
("R" smerge-kill-current)
|
||||
("q" nil :color blue))))
|
||||
("q" nil :color blue)))
|
||||
|
@ -37,7 +37,7 @@
|
||||
;;;###autoload (autoload '+workspace:delete "feature/workspaces/autoload/evil" nil t)
|
||||
(evil-define-command +workspace:delete ()
|
||||
"Ex wrapper around `+workspace/delete'."
|
||||
(interactive "<a>") (+workspace/delete (+workspace-current-name)))
|
||||
(interactive) (+workspace/delete (+workspace-current-name)))
|
||||
|
||||
;;;###autoload (autoload '+workspace:switch-next "feature/workspaces/autoload/evil" nil t)
|
||||
(evil-define-command +workspace:switch-next (&optional count)
|
||||
|
@ -1,20 +1,70 @@
|
||||
;;; feature/workspaces/autoload/workspaces.el -*- lexical-binding: t; -*-
|
||||
|
||||
(defvar +workspace-workspace-file "_workspaces"
|
||||
(defvar +workspace-data-file "_workspaces"
|
||||
"The file basename in which to store single workspace perspectives.")
|
||||
|
||||
(defvar +workspace--last nil)
|
||||
(defvar +workspace--index 0)
|
||||
|
||||
(defface +workspace-tab-selected-face
|
||||
'((t (:inherit 'highlight)))
|
||||
;;
|
||||
(defface +workspace-tab-selected-face '((t (:inherit 'highlight)))
|
||||
"The face for selected tabs displayed by `+workspace/display'"
|
||||
:group 'doom)
|
||||
|
||||
(defface +workspace-tab-face
|
||||
'((t (:inherit 'default)))
|
||||
(defface +workspace-tab-face '((t (:inherit 'default)))
|
||||
"The face for selected tabs displayed by `+workspace/display'"
|
||||
:group 'doom)
|
||||
|
||||
|
||||
;;
|
||||
;; Library
|
||||
;;
|
||||
|
||||
(defun +workspace--protected-p (name)
|
||||
(equal name persp-nil-name))
|
||||
|
||||
(defun +workspace--generate-id ()
|
||||
(or (cl-loop for name in (+workspace-list-names)
|
||||
when (string-match-p "^#[0-9]+$" name)
|
||||
maximize (string-to-number (substring name 1)) into max
|
||||
finally return (if max (1+ max)))
|
||||
1))
|
||||
|
||||
|
||||
;; --- Predicates -------------------------
|
||||
|
||||
;;;###autoload
|
||||
(defalias #'+workspace-p #'persp-p "Return t if OBJ is a perspective hash table.")
|
||||
|
||||
;;;###autoload
|
||||
(defun +workspace-exists-p (name)
|
||||
"Returns t if NAME is the name of an existing workspace."
|
||||
(cl-assert (stringp name) t)
|
||||
(member name (+workspace-list-names)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +workspace-contains-buffer-p (buffer &optional workspace)
|
||||
"Return non-nil if buffer is in workspace (defaults to current workspace)."
|
||||
(persp-contain-buffer-p buffer (or workspace (+workspace-current)) nil))
|
||||
|
||||
|
||||
;; --- Getters ----------------------------
|
||||
|
||||
;;;###autoload
|
||||
(defun +workspace-get (name &optional noerror)
|
||||
"Returns a workspace (perspective hash table) named NAME."
|
||||
(when-let (persp (persp-get-by-name name))
|
||||
(cond ((+workspace-p persp) persp)
|
||||
((not noerror) (error "'%s' is an invalid workspace" name)))))
|
||||
|
||||
;;;###autoload
|
||||
(defalias '+workspace-current #'get-current-persp)
|
||||
|
||||
;;;###autoload
|
||||
(defun +workspace-current-name ()
|
||||
"Get the name of the current workspace."
|
||||
(safe-persp-name (get-current-persp)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +workspace-list ()
|
||||
"Return a list of workspace structs."
|
||||
@ -36,123 +86,92 @@ PERSP can be a string (name of a workspace) or a perspective hash (satisfies
|
||||
|
||||
If PERSP is t, then return a list of orphaned buffers associated with no
|
||||
perspectives."
|
||||
(unless persp
|
||||
(setq persp (get-current-persp)))
|
||||
(let ((persp (or persp (+workspace-current))))
|
||||
(if (eq persp t)
|
||||
(cl-remove-if #'persp--buffer-in-persps (buffer-list))
|
||||
(when (stringp persp)
|
||||
(setq persp (+workspace-get persp t)))
|
||||
(cl-assert (+workspace-p persp) t)
|
||||
(cl-loop for buf in (buffer-list)
|
||||
if (persp-contain-buffer-p buf persp)
|
||||
collect buf)))
|
||||
if (+workspace-contains-buffer-p buf persp)
|
||||
collect buf))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +workspace-p (obj)
|
||||
"Return t if OBJ is a perspective hash table."
|
||||
(and obj
|
||||
(cl-struct-p obj)
|
||||
(perspective-p obj)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +workspace-exists-p (name)
|
||||
"Returns t if NAME is the name of an existing workspace."
|
||||
(when (symbolp name)
|
||||
(setq name (symbol-name name)))
|
||||
(unless (stringp name)
|
||||
(error "Expected a string, got a %s" (type-of name)))
|
||||
(member name (+workspace-list-names)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +workspace-get (name &optional noerror)
|
||||
"Returns a workspace (perspective hash table) named NAME."
|
||||
(unless (equal name persp-nil-name)
|
||||
(let ((persp (persp-get-by-name name)))
|
||||
(when (and (not noerror)
|
||||
(or (null persp)
|
||||
(equal persp persp-not-persp)))
|
||||
(error "%s is not an available workspace" name))
|
||||
persp)))
|
||||
|
||||
;;;###autoload
|
||||
(defalias '+workspace-current #'get-current-persp)
|
||||
|
||||
;;;###autoload
|
||||
(defun +workspace-current-name ()
|
||||
"Get the name of the currently active workspace."
|
||||
(safe-persp-name (get-current-persp)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +workspace-contains-buffer-p (&optional buffer workspace)
|
||||
"Return non-nil if buffer is in workspace (defaults to current workspace)."
|
||||
(unless workspace
|
||||
(setq workspace (+workspace-current)))
|
||||
(persp-contain-buffer-p buffer workspace nil))
|
||||
;; --- Actions ----------------------------
|
||||
|
||||
;;;###autoload
|
||||
(defun +workspace-load (name)
|
||||
"Loads and inserts a single workspace (named NAME) into the current session.
|
||||
Can only retrieve perspectives that were explicitly saved with
|
||||
`+workspace-save'.
|
||||
"Loads a single workspace (named NAME) into the current session. Can only
|
||||
retrieve perspectives that were explicitly saved with `+workspace-save'.
|
||||
|
||||
Returns t if successful, nil otherwise."
|
||||
(unless (+workspace-exists-p name)
|
||||
(persp-load-from-file-by-names +workspace-workspace-file *persp-hash* (list name)))
|
||||
(when (+workspace-exists-p name)
|
||||
(error "A workspace named '%s' already exists." name))
|
||||
(persp-load-from-file-by-names
|
||||
(expand-file-name +workspace-data-file persp-save-dir)
|
||||
*persp-hash* (list name))
|
||||
(+workspace-exists-p name))
|
||||
|
||||
;;;###autoload
|
||||
(defun +workspace-load-session (&optional name)
|
||||
"Replace current session with the entire session named NAME. If NAME is nil,
|
||||
use `persp-auto-save-fname'."
|
||||
(persp-load-state-from-file (or name persp-auto-save-fname)))
|
||||
(persp-load-state-from-file
|
||||
(expand-file-name (or name persp-auto-save-fname) persp-save-dir)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +workspace-save (name)
|
||||
"Saves a single workspace (TARGET) from the current session. Can be loaded
|
||||
again with `+workspace-load'. TARGET can be the string name of a workspace or
|
||||
its perspective hash table.
|
||||
"Saves a single workspace (NAME) from the current session. Can be loaded again
|
||||
with `+workspace-load'. NAME can be the string name of a workspace or its
|
||||
perspective hash table.
|
||||
|
||||
Returns t on success, nil otherwise."
|
||||
(unless (+workspace-exists-p name)
|
||||
(error "%s is not an available workspace" name))
|
||||
(persp-save-to-file-by-names
|
||||
+workspace-workspace-file *persp-hash* (list name) t)
|
||||
(memq name (persp-list-persp-names-in-file (concat persp-save-dir +workspace-workspace-file))))
|
||||
(error "'%s' is an invalid workspace" name))
|
||||
(let ((fname (expand-file-name +workspace-data-file persp-save-dir)))
|
||||
(persp-save-to-file-by-names fname *persp-hash* (list name))
|
||||
(and (member name (persp-list-persp-names-in-file fname))
|
||||
t)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +workspace-save-session (&optional name)
|
||||
"Save a whole session as NAME. If NAME is nil, use `persp-auto-save-fname'.
|
||||
Return t on success, nil otherwise."
|
||||
(when (or (not name)
|
||||
(let ((fname (expand-file-name (or name persp-auto-save-fname)
|
||||
persp-save-dir))
|
||||
(persp-auto-save-opt
|
||||
(if (or (not name)
|
||||
(equal name persp-auto-save-fname))
|
||||
(setq name persp-auto-save-fname
|
||||
persp-auto-save-opt 0))
|
||||
(and (persp-save-state-to-file name) t))
|
||||
0
|
||||
persp-auto-save-opt)))
|
||||
(and (persp-save-state-to-file fname) t)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +workspace-new (name)
|
||||
"Create a new workspace named NAME. If one already exists, return nil.
|
||||
Otherwise return t on success, nil otherwise."
|
||||
(when (+workspace-protected-p name)
|
||||
(when (+workspace--protected-p name)
|
||||
(error "Can't create a new '%s' workspace" name))
|
||||
(unless (+workspace-exists-p name)
|
||||
(and (persp-add-new name) t)))
|
||||
(when (+workspace-exists-p name)
|
||||
(error "A workspace named '%s' already exists" name))
|
||||
(and (persp-add-new name) t))
|
||||
|
||||
;;;###autoload
|
||||
(defun +workspace-rename (name new-name)
|
||||
"Rename the current workspace named NAME to NEW-NAME. Returns old name on
|
||||
success, nil otherwise."
|
||||
(when (+workspace-protected-p name)
|
||||
(when (+workspace--protected-p name)
|
||||
(error "Can't rename '%s' workspace" name))
|
||||
(persp-rename new-name (+workspace-get name)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +workspace-delete (name &optional inhibit-kill-p)
|
||||
"Delete the workspace denoted by TARGET, which can be the name of a
|
||||
perspective or its hash table."
|
||||
(when (+workspace-protected-p name)
|
||||
"Delete the workspace denoted by NAME, which can be the name of a perspective
|
||||
or its hash table. If INHIBIT-KILL-P is non-nil, don't kill this workspace's
|
||||
buffers."
|
||||
(when (+workspace--protected-p name)
|
||||
(error "Can't delete '%s' workspace" name))
|
||||
(+workspace-get name) ;; error checking
|
||||
(persp-kill name inhibit-kill-p))
|
||||
(+workspace-get name) ; error checking
|
||||
(persp-kill name inhibit-kill-p)
|
||||
(not (+workspace-exists-p name)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +workspace-switch (name &optional auto-create-p)
|
||||
@ -168,17 +187,6 @@ perspective or its hash table."
|
||||
+workspaces-main)))
|
||||
(persp-frame-switch name))
|
||||
|
||||
(defun +workspace--generate-id ()
|
||||
(or (cl-loop for name in (+workspace-list-names)
|
||||
when (string-match-p "^#[0-9]+$" name)
|
||||
maximize (string-to-number (substring name 1)) into max
|
||||
finally return (if max (1+ max)))
|
||||
1))
|
||||
|
||||
(defun +workspace-protected-p (name)
|
||||
(or (equal name persp-nil-name)
|
||||
(equal name +workspaces-main)))
|
||||
|
||||
|
||||
;;
|
||||
;; Interactive commands
|
||||
@ -192,9 +200,10 @@ current workspace (by name) from session files."
|
||||
(list
|
||||
(if current-prefix-arg
|
||||
(+workspace-current-name)
|
||||
(completing-read "Workspace to load: "
|
||||
(completing-read
|
||||
"Workspace to load: "
|
||||
(persp-list-persp-names-in-file
|
||||
(concat persp-save-dir +workspace-workspace-file))))))
|
||||
(expand-file-name +workspace-data-file persp-save-dir))))))
|
||||
(if (not (+workspace-load name))
|
||||
(+workspace-error (format "Couldn't load workspace %s" name))
|
||||
(+workspace/switch-to name)
|
||||
@ -272,20 +281,30 @@ workspace to delete."
|
||||
nil nil current-name)
|
||||
current-name))))
|
||||
(condition-case ex
|
||||
(if (not (+workspace-delete name))
|
||||
(error "Couldn't delete %s workspace" name)
|
||||
(+workspace-message
|
||||
(let ((workspaces (length (+workspace-list-names))))
|
||||
(cond ((> workspaces 1)
|
||||
(+workspace-delete name)
|
||||
(+workspace-switch
|
||||
(if (+workspace-exists-p +workspace--last)
|
||||
(+workspace-switch +workspace--last)
|
||||
(+workspace-switch +workspaces-main t))
|
||||
(+workspace-message (format "Deleted '%s' workspace" name) 'success))
|
||||
+workspace--last
|
||||
(car (+workspace-list-names))))
|
||||
(format "Deleted '%s' workspace" name))
|
||||
((= workspaces 1)
|
||||
(format "Can't delete the last workspace!"))
|
||||
(t
|
||||
(+workspace-delete name)
|
||||
(+workspace-switch +workspaces-main t)
|
||||
(switch-to-buffer (doom-fallback-buffer))
|
||||
(format "No workspaces detected! Auto-creating '%s' workspace" +workspaces-main))))
|
||||
'success)
|
||||
('error (+workspace-error (cadr ex) t))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +workspace/kill-session ()
|
||||
"Delete the current session, clears all workspaces, windows and buffers."
|
||||
(interactive)
|
||||
(unless (cl-every #'+workspace-delete
|
||||
(delete +workspaces-main (+workspace-list-names)))
|
||||
(unless (cl-every #'+workspace-delete (+workspace-list-names))
|
||||
(+workspace-error "Could not clear session"))
|
||||
(+workspace-switch +workspaces-main t)
|
||||
(doom/kill-all-buffers)
|
||||
@ -388,7 +407,7 @@ the workspace and move to the next."
|
||||
(if (doom-popup-p)
|
||||
(doom/popup-close)
|
||||
(let ((current-persp-name (+workspace-current-name)))
|
||||
(cond ((or (+workspace-protected-p current-persp-name)
|
||||
(cond ((or (+workspace--protected-p current-persp-name)
|
||||
(> (length (doom-visible-windows)) 1))
|
||||
(if (bound-and-true-p evil-mode)
|
||||
(evil-window-delete)
|
||||
@ -397,15 +416,17 @@ the workspace and move to the next."
|
||||
(+workspace/delete current-persp-name))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +workspace/cleanup ()
|
||||
"Clean up orphaned buffers and processes."
|
||||
(defun +workspace/close-workspace-or-frame ()
|
||||
"Close the current workspace. If it's the last, delete the frame instead."
|
||||
(interactive)
|
||||
(let ((buffers (cl-remove-if #'persp--buffer-in-persps (buffer-list)))
|
||||
(n (doom-kill-process-buffers)))
|
||||
(mapc #'kill-buffer buffers)
|
||||
(when (called-interactively-p 'any)
|
||||
(message "Cleaned up %d buffers and %d processes"
|
||||
(length buffers) n))))
|
||||
(let ((frames (length (frame-list)))
|
||||
(workspaces (length (+workspace-list-names))))
|
||||
(cond ((> workspaces 1)
|
||||
(call-interactively #'+workspace/delete))
|
||||
((> frames 1)
|
||||
(call-interactively #'delete-frame))
|
||||
(t
|
||||
(error "Can't delete last frame.")))))
|
||||
|
||||
|
||||
;;
|
||||
|
@ -1,7 +1,7 @@
|
||||
;;; lang/cc/autoload.el -*- lexical-binding: t; -*-
|
||||
|
||||
;;;###autoload
|
||||
(defun +cc*lineup-arglist (orig-fun &rest args)
|
||||
(defun +cc*align-lambda-arglist (orig-fun &rest args)
|
||||
"Improve indentation of continued C++11 lambda function opened as argument."
|
||||
(if (and (eq major-mode 'c++-mode)
|
||||
(ignore-errors
|
||||
@ -21,59 +21,62 @@
|
||||
(backward-char)
|
||||
(looking-at-p "[^ \t]>"))
|
||||
(forward-char)
|
||||
(call-interactively 'self-insert-command)))
|
||||
|
||||
(defun +cc--copy-face (new-face face)
|
||||
"Define NEW-FACE from existing FACE."
|
||||
(copy-face face new-face)
|
||||
(eval `(defvar ,new-face nil))
|
||||
(set new-face new-face))
|
||||
|
||||
;;;###autoload
|
||||
(defun +cc|extra-fontify-c++ ()
|
||||
;; We could place some regexes into `c-mode-common-hook', but
|
||||
;; note that their evaluation order matters.
|
||||
;; NOTE modern-cpp-font-lock will eventually supercede some of these rules
|
||||
(font-lock-add-keywords
|
||||
nil '(;; c++11 string literals
|
||||
;; L"wide string"
|
||||
;; L"wide string with UNICODE codepoint: \u2018"
|
||||
;; u8"UTF-8 string", u"UTF-16 string", U"UTF-32 string"
|
||||
("\\<\\([LuU8]+\\)\".*?\"" 1 font-lock-keyword-face)
|
||||
;; R"(user-defined literal)"
|
||||
;; R"( a "quot'd" string )"
|
||||
;; R"delimiter(The String Data" )delimiter"
|
||||
;; R"delimiter((a-z))delimiter" is equivalent to "(a-z)"
|
||||
("\\(\\<[uU8]*R\"[^\\s-\\\\()]\\{0,16\\}(\\)" 1 font-lock-keyword-face t) ; start delimiter
|
||||
( "\\<[uU8]*R\"[^\\s-\\\\()]\\{0,16\\}(\\(.*?\\))[^\\s-\\\\()]\\{0,16\\}\"" 1 font-lock-string-face t) ; actual string
|
||||
( "\\<[uU8]*R\"[^\\s-\\\\()]\\{0,16\\}(.*?\\()[^\\s-\\\\()]\\{0,16\\}\"\\)" 1 font-lock-keyword-face t) ; end delimiter
|
||||
) t))
|
||||
|
||||
;;;###autoload
|
||||
(defun +cc|extra-fontify-c/c++ ()
|
||||
(font-lock-add-keywords
|
||||
nil '(;; PREPROCESSOR_CONSTANT, PREPROCESSORCONSTANT
|
||||
("\\<[A-Z]*_[A-Z_]+\\>" . font-lock-constant-face)
|
||||
("\\<[A-Z]\\{3,\\}\\>" . font-lock-constant-face)
|
||||
;; integer/float/scientific numbers
|
||||
("\\<\\([\\-+]*[0-9\\.]+\\)\\>" 1 font-lock-constant-face t)
|
||||
("\\<\\([\\-+]*[0-9\\.]+\\)\\(f\\)\\>"
|
||||
(1 font-lock-constant-face t)
|
||||
(2 font-lock-keyword-face t))
|
||||
("\\<\\([\\-+]*[0-9\\.]+\\)\\([eE]\\)\\([\\-+]?[0-9]+\\)\\>"
|
||||
(1 font-lock-constant-face t)
|
||||
(2 font-lock-keyword-face t)
|
||||
(3 font-lock-constant-face t))
|
||||
) t))
|
||||
(call-interactively #'self-insert-command)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +cc-sp-point-is-template-p (id action context)
|
||||
"Return t if point is in the right place for C++ angle-brackets."
|
||||
(and (sp-in-code-p id action context)
|
||||
(sp-point-after-word-p id action context)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +cc-sp-point-after-include-p (id action context)
|
||||
"Return t if point is in an #include."
|
||||
(and (sp-in-code-p id action context)
|
||||
(save-excursion
|
||||
(goto-char (line-beginning-position))
|
||||
(looking-at-p "[ ]*#include[^<]+"))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +cc-c-lineup-inclass (_langelem)
|
||||
"Indent privacy keywords at same level as class properties."
|
||||
(if (memq major-mode '(c-mode c++-mode))
|
||||
(let ((inclass (assq 'inclass c-syntactic-context)))
|
||||
(save-excursion
|
||||
(goto-char (c-langelem-pos inclass))
|
||||
(if (or (looking-at "struct")
|
||||
(looking-at "typedef struct"))
|
||||
'+
|
||||
'++)))
|
||||
'+))
|
||||
|
||||
|
||||
;;
|
||||
;; Hooks
|
||||
;;
|
||||
|
||||
;;;###autoload
|
||||
(defun +cc|fontify-constants ()
|
||||
"Better fontification for preprocessor constants"
|
||||
(font-lock-add-keywords
|
||||
nil '(("\\<[A-Z]*_[A-Z_]+\\>" . font-lock-constant-face)
|
||||
("\\<[A-Z]\\{3,\\}\\>" . font-lock-constant-face))
|
||||
t))
|
||||
|
||||
;;;###autoload
|
||||
(defun +cc|irony-init-compile-options ()
|
||||
"Initialize compiler options for irony-mode. It searches for the nearest
|
||||
compilation database and initailizes it. If none was found, it uses
|
||||
`+cc-c++-compiler-options'.
|
||||
|
||||
See https://github.com/Sarcasm/irony-mode#compilation-database for details on
|
||||
compilation dbs."
|
||||
(when (memq major-mode '(c-mode c++-mode objc-mode))
|
||||
(require 'irony-cdb)
|
||||
(unless (irony-cdb-autosetup-compile-options)
|
||||
(irony-cdb--update-compile-options
|
||||
(append (delq nil (cdr-safe (assq major-mode +cc-compiler-options)))
|
||||
(cl-loop for path in +cc-include-paths
|
||||
nconc (list "-I" path)))
|
||||
(doom-project-root)))))
|
||||
|
||||
|
@ -1,12 +1,35 @@
|
||||
;;; lang/cc/config.el --- c, c++, and obj-c -*- lexical-binding: t; -*-
|
||||
|
||||
(defvar +cc-include-paths (list "include/")
|
||||
"A list of paths, relative to a project root, to search for headers in C/C++.
|
||||
Paths can be absolute.
|
||||
|
||||
The purpose of this variable is to ensure syntax checkers and code-completion
|
||||
knows where to look for headers.")
|
||||
|
||||
(defvar +cc-compiler-options
|
||||
`((c-mode . nil)
|
||||
(c++-mode
|
||||
. ,(list "-std=c++11" ; use C++11 by default
|
||||
(when IS-MAC
|
||||
;; NOTE beware: you'll get abi-inconsistencies when passing
|
||||
;; std-objects to libraries linked with libstdc++ (e.g. if you
|
||||
;; use boost which wasn't compiled with libc++)
|
||||
(list "-stdlib=libc++"))))
|
||||
(objc-mode . nil))
|
||||
"A list of default compiler options for the C family. These are ignored if a
|
||||
compilation database is present in the project.")
|
||||
|
||||
|
||||
;;
|
||||
;; Plugins
|
||||
;;
|
||||
|
||||
(def-package! cc-mode
|
||||
:commands (c-mode c++-mode objc-mode java-mode)
|
||||
:mode ("\\.mm" . objc-mode)
|
||||
:init
|
||||
(setq-default c-basic-offset tab-width)
|
||||
|
||||
(defun +cc--c++-header-file-p ()
|
||||
:preface
|
||||
(defun +cc-c++-header-file-p ()
|
||||
(and buffer-file-name
|
||||
(equal (file-name-extension buffer-file-name) "h")
|
||||
(or (file-exists-p (expand-file-name
|
||||
@ -17,89 +40,68 @@
|
||||
(projectile-current-project-files))))
|
||||
(equal (file-name-extension file) "cpp")))))
|
||||
|
||||
(defun +cc--objc-header-file-p ()
|
||||
(defun +cc-objc-header-file-p ()
|
||||
(and buffer-file-name
|
||||
(equal (file-name-extension buffer-file-name) "h")
|
||||
(re-search-forward "@\\<interface\\>" magic-mode-regexp-match-limit t)))
|
||||
|
||||
;; Auto-detect C++/Obj-C header files
|
||||
(push (cons #'+cc--c++-header-file-p 'c++-mode) magic-mode-alist)
|
||||
(push (cons #'+cc--objc-header-file-p 'objc-mode) magic-mode-alist)
|
||||
(push (cons #'+cc-c++-header-file-p 'c++-mode) magic-mode-alist)
|
||||
(push (cons #'+cc-objc-header-file-p 'objc-mode) magic-mode-alist)
|
||||
|
||||
:init
|
||||
(setq-default c-basic-offset tab-width)
|
||||
|
||||
:config
|
||||
(setq c-tab-always-indent nil
|
||||
c-electric-flag nil)
|
||||
|
||||
(set! :electric '(c-mode c++-mode objc-mode java-mode)
|
||||
:chars '(?\n ?\}))
|
||||
|
||||
(set! :company-backend
|
||||
'(c-mode c++-mode objc-mode)
|
||||
'(company-irony-c-headers company-irony))
|
||||
|
||||
(add-hook 'c-mode-common-hook #'rainbow-delimiters-mode)
|
||||
(add-hook 'c-mode-hook #'highlight-numbers-mode) ; fontify numbers in C
|
||||
(add-hook 'c++-mode-hook #'+cc|extra-fontify-c++) ; fontify C++11 string literals
|
||||
;;; Style/formatting
|
||||
;; C/C++ style settings
|
||||
(c-toggle-electric-state -1)
|
||||
(c-toggle-auto-newline -1)
|
||||
(c-set-offset 'substatement-open '0) ; don't indent brackets
|
||||
(c-set-offset 'inline-open '+)
|
||||
(c-set-offset 'block-open '+)
|
||||
(c-set-offset 'brace-list-open '+)
|
||||
(c-set-offset 'case-label '+)
|
||||
(c-set-offset 'access-label '-)
|
||||
(c-set-offset 'arglist-intro '+)
|
||||
(c-set-offset 'arglist-close '0)
|
||||
;; Indent privacy keywords at same level as class properties
|
||||
;; (c-set-offset 'inclass #'+cc-c-lineup-inclass)
|
||||
|
||||
;;; Better fontification (also see `modern-cpp-font-lock')
|
||||
(add-hook 'c-mode-common-hook #'rainbow-delimiters-mode)
|
||||
(add-hook! (c-mode c++-mode) #'highlight-numbers-mode)
|
||||
(add-hook! (c-mode c++-mode) #'+cc|fontify-constants)
|
||||
|
||||
;; Improve indentation of inline lambdas in C++11
|
||||
(advice-add #'c-lineup-arglist :around #'+cc*align-lambda-arglist)
|
||||
|
||||
;;; Keybindings
|
||||
;; Completely disable electric keys because it interferes with smartparens and
|
||||
;; custom bindings. We'll do this ourselves.
|
||||
(setq c-tab-always-indent nil
|
||||
c-electric-flag nil)
|
||||
(dolist (key '("#" "{" "}" "/" "*" ";" "," ":" "(" ")"))
|
||||
(define-key c-mode-base-map key nil))
|
||||
;; Smartparens and cc-mode both try to autoclose angle-brackets intelligently.
|
||||
;; The result isn't very intelligent (causes redundant characters), so just do
|
||||
;; it ourselves.
|
||||
(map! :map c++-mode-map
|
||||
"<" nil
|
||||
:i ">" #'+cc/autoclose->-maybe)
|
||||
|
||||
;; ...and leave it to smartparens
|
||||
(sp-with-modes '(c-mode c++-mode objc-mode java-mode)
|
||||
(sp-local-pair "<" ">" :when '(+cc-sp-point-is-template-p +cc-sp-point-after-include-p))
|
||||
(sp-local-pair "/*" "*/" :post-handlers '(("||\n[i]" "RET") ("| " "SPC")))
|
||||
;; Doxygen blocks
|
||||
(sp-local-pair "/**" "*/" :post-handlers '(("||\n[i]" "RET") ("||\n[i]" "SPC")))
|
||||
(sp-local-pair "/*!" "*/" :post-handlers '(("||\n[i]" "RET") ("[d-1]< | " "SPC"))))
|
||||
|
||||
;; Improve indentation of inline lambdas in C++11
|
||||
(advice-add #'c-lineup-arglist :around #'+cc*lineup-arglist)
|
||||
|
||||
;; C/C++ style settings
|
||||
(c-toggle-electric-state -1)
|
||||
(c-toggle-auto-newline -1)
|
||||
(c-set-offset 'substatement-open '0) ; brackets should be at same indentation level as the statements they open
|
||||
(c-set-offset 'inline-open '+)
|
||||
(c-set-offset 'block-open '+)
|
||||
(c-set-offset 'brace-list-open '+) ; all "opens" should be indented by the c-indent-level
|
||||
(c-set-offset 'case-label '+) ; indent case labels by c-indent-level, too
|
||||
(c-set-offset 'access-label '-)
|
||||
(c-set-offset 'arglist-intro '+)
|
||||
(c-set-offset 'arglist-close '0)
|
||||
|
||||
(defun +cc--c-lineup-inclass (_langelem)
|
||||
(if (memq major-mode '(c-mode c++-mode))
|
||||
(let ((inclass (assq 'inclass c-syntactic-context)))
|
||||
(save-excursion
|
||||
(goto-char (c-langelem-pos inclass))
|
||||
(if (or (looking-at "struct")
|
||||
(looking-at "typedef struct"))
|
||||
'+
|
||||
'++)))
|
||||
'+))
|
||||
(c-set-offset 'inclass #'+cc--c-lineup-inclass)
|
||||
|
||||
|
||||
;; Certain electric mappings interfere with smartparens and custom bindings,
|
||||
;; so unbind them
|
||||
(map! :map c-mode-map
|
||||
"DEL" nil
|
||||
"#" #'self-insert-command
|
||||
"{" #'self-insert-command
|
||||
"}" #'self-insert-command
|
||||
"/" #'self-insert-command
|
||||
"*" #'self-insert-command
|
||||
";" #'self-insert-command
|
||||
"," #'self-insert-command
|
||||
":" #'self-insert-command
|
||||
"(" #'self-insert-command
|
||||
")" #'self-insert-command
|
||||
|
||||
:map c++-mode-map
|
||||
"}" nil
|
||||
|
||||
;; Smartparens and cc-mode both try to autoclose angle-brackets
|
||||
;; intelligently. The result isn't very intelligent (causes redundant
|
||||
;; characters), so just do it ourselves.
|
||||
"<" nil
|
||||
:map (c-mode-base-map c++-mode-map)
|
||||
:i ">" #'+cc/autoclose->-maybe))
|
||||
(sp-local-pair "/*!" "*/" :post-handlers '(("||\n[i]" "RET") ("[d-1]< | " "SPC")))))
|
||||
|
||||
|
||||
(def-package! modern-cpp-font-lock
|
||||
@ -113,29 +115,25 @@
|
||||
:preface
|
||||
(setq irony-server-install-prefix (concat doom-etc-dir "irony-server/"))
|
||||
:init
|
||||
(defun +cc|init-irony-mode ()
|
||||
(when (and (memq major-mode '(c-mode c++-mode objc-mode))
|
||||
(file-directory-p irony-server-install-prefix))
|
||||
(irony-mode +1)))
|
||||
(add-hook 'c-mode-common-hook #'+cc|init-irony-mode)
|
||||
(add-hook! (c-mode c++-mode objc-mode) #'irony-mode)
|
||||
:config
|
||||
(add-hook! 'irony-mode-hook #'(irony-eldoc flycheck-mode))
|
||||
(unless (file-directory-p irony-server-install-prefix)
|
||||
(warn "irony-mode: server isn't installed; run M-x irony-install-server"))
|
||||
|
||||
(defun +cc|init-c++11-clang-options ()
|
||||
(make-local-variable 'irony-additional-clang-options)
|
||||
(cl-pushnew "-std=c++11" irony-additional-clang-options :test 'equal))
|
||||
(add-hook 'c++-mode-hook #'+cc|init-c++11-clang-options)
|
||||
;; Initialize compilation database, if present. Otherwise, fall back on
|
||||
;; `+cc-compiler-options'.
|
||||
(add-hook 'irony-mode-hook #'+cc|irony-init-compile-options))
|
||||
|
||||
(map! :map irony-mode-map
|
||||
[remap completion-at-point] #'counsel-irony
|
||||
[remap complete-symbol] #'counsel-irony))
|
||||
|
||||
(def-package! irony-eldoc :after irony)
|
||||
(def-package! irony-eldoc
|
||||
:after irony
|
||||
:config (add-hook 'irony-mode-hook #'irony-eldoc))
|
||||
|
||||
(def-package! flycheck-irony
|
||||
:when (featurep! :feature syntax-checker)
|
||||
:after irony
|
||||
:config (flycheck-irony-setup))
|
||||
:config
|
||||
(add-hook 'irony-mode-hook #'flycheck-mode)
|
||||
(flycheck-irony-setup))
|
||||
|
||||
|
||||
;;
|
||||
@ -181,7 +179,6 @@
|
||||
(def-package! company-irony-c-headers :after company-irony)
|
||||
|
||||
(def-package! company-glsl
|
||||
:when (featurep! :completion company)
|
||||
:after glsl-mode
|
||||
:config
|
||||
(if (executable-find "glslangValidator")
|
||||
|
@ -29,12 +29,7 @@
|
||||
|
||||
|
||||
(def-package! dockerfile-mode
|
||||
:mode "/Dockerfile$"
|
||||
:config
|
||||
;; TODO
|
||||
;; (set! :build 'build-image 'dockerfile-mode '+data/dockerfile-build
|
||||
;; :when '+data-dockerfile-p)
|
||||
)
|
||||
:mode "/Dockerfile$")
|
||||
|
||||
|
||||
;; For ROM hacking or debugging
|
||||
|
@ -1,9 +1,5 @@
|
||||
;;; lang/go/autoload.el -*- lexical-binding: t; -*-
|
||||
|
||||
;;;###autoload
|
||||
;; TODO (defun +go/build ())
|
||||
|
||||
|
||||
;;
|
||||
;; Tests
|
||||
;;
|
||||
|
@ -4,45 +4,64 @@
|
||||
:mode "\\.go$"
|
||||
:interpreter "go"
|
||||
:config
|
||||
(setq gofmt-command "goimports")
|
||||
|
||||
(add-hook 'go-mode-hook #'flycheck-mode)
|
||||
|
||||
(setq gofmt-command "goimports")
|
||||
(if (not (executable-find "goimports"))
|
||||
(warn "go-mode: couldn't find goimports; no code formatting/fixed imports on save")
|
||||
(add-hook! go-mode (add-hook 'before-save-hook #'gofmt-before-save nil t)))
|
||||
|
||||
(set! :build 'go-build 'go-mode #'+go/build)
|
||||
(set! :repl 'go-mode #'gorepl-run)
|
||||
(set! :jump 'go-mode
|
||||
:definition #'go-guru-definition
|
||||
:references #'go-guru-referrers
|
||||
:documentation #'godoc-at-point)
|
||||
|
||||
(def-menu! +go/refactor-menu
|
||||
"Refactoring commands for `go-mode' buffers."
|
||||
'(("Add import" :exec go-import-add :region nil)
|
||||
("Remove unused imports" :exec go-remove-unused-imports :region nil)
|
||||
("Format buffer (gofmt)" :exec go-gofmt))
|
||||
:prompt "Refactor: ")
|
||||
|
||||
(def-menu! +go/build-menu
|
||||
"Build/compilation commands for `go-mode' buffers."
|
||||
'(("Build project" :exec "go build")
|
||||
("Build & run project" :exec "go run")
|
||||
("Clean files" :exec "go clean"))
|
||||
:prompt "Run test: ")
|
||||
|
||||
(def-menu! +go/test-menu
|
||||
"Test commands for `go-mode' buffers."
|
||||
'(("Last test" :exec +go/test-rerun)
|
||||
("All tests" :exec +go/test-all)
|
||||
("Single test" :exec +go/test-single)
|
||||
("Nested test" :exec +go/test-nested))
|
||||
:prompt "Run test: ")
|
||||
|
||||
(def-menu! +go/help-menu
|
||||
"Help and information commands for `go-mode' buffers."
|
||||
'(("Go to imports" :exec go-goto-imports)
|
||||
("Lookup in godoc" :exec godoc-at-point)
|
||||
("Describe this" :exec go-guru-describe)
|
||||
("List free variables" :exec go-guru-freevars)
|
||||
("What does this point to" :exec go-guru-pointsto)
|
||||
("Implements relations for package types" :exec go-guru-implements :region nil)
|
||||
("List peers for channel" :exec go-guru-peers)
|
||||
("List references to object" :exec go-guru-referrers)
|
||||
("Which errors" :exec go-guru-whicerrs)
|
||||
("What query" :exec go-guru-what)
|
||||
("Show callers of this function" :exec go-guru-callers :region nil)
|
||||
("Show callees of this function" :exec go-guru-callees :region nil)))
|
||||
|
||||
(map! :map go-mode-map
|
||||
:n "gd" #'go-guru-definition
|
||||
:n "gD" #'go-guru-referrers
|
||||
(:localleader
|
||||
:localleader
|
||||
"r" #'+go/refactor-menu
|
||||
"b" #'+go/build-menu
|
||||
"h" #'+go/help-menu
|
||||
"t" #'+go/test-menu
|
||||
:n "gr" #'go-play-buffer
|
||||
:v "gr" #'go-play-region
|
||||
(:prefix "f"
|
||||
:n "i" #'go-goto-imports
|
||||
:n "h" #'godoc-at-point
|
||||
:n "d" #'go-guru-describe
|
||||
:n "v" #'go-guru-freevars
|
||||
:n "I" #'go-guru-implements
|
||||
:n "p" #'go-guru-peers
|
||||
:n "r" #'go-guru-referrers
|
||||
:n "t" #'go-guru-pointsto
|
||||
:n "s" #'go-guru-callstack
|
||||
:n "e" #'go-guru-whicherrs
|
||||
:n "c" #'go-guru-callers
|
||||
:n "C" #'go-guru-callees)
|
||||
(:prefix "r"
|
||||
:n "a" #'go-import-add
|
||||
:n "i" #'go-remove-unused-imports
|
||||
:nv "f" #'gofmt)
|
||||
(:prefix "t"
|
||||
:n "r" #'+go/test-rerun
|
||||
:n "a" #'+go/test-all
|
||||
:n "s" #'+go/test-single
|
||||
:n "n" #'+go/test-nested))))
|
||||
:v "gr" #'go-play-region))
|
||||
|
||||
|
||||
(def-package! go-eldoc
|
||||
|
@ -12,7 +12,7 @@
|
||||
(add-hook! 'intero-mode-hook #'(flycheck-mode eldoc-mode))
|
||||
|
||||
(set! :popup "^intero:backend:" :regex t :size 12)
|
||||
(set! :jump :definition #'intero-goto-definition))
|
||||
(set! :jump 'haskell-mode :definition #'intero-goto-definition))
|
||||
|
||||
|
||||
(def-package! hindent
|
||||
|
@ -1,5 +1,13 @@
|
||||
;;; lang/haskell/config.el -*- lexical-binding: t; -*-
|
||||
|
||||
(cond ((featurep! +intero) (load! +intero))
|
||||
((featurep! +dante) (load! +dante)))
|
||||
|
||||
|
||||
;;
|
||||
;; Common plugins
|
||||
;;
|
||||
|
||||
(def-package! haskell-mode
|
||||
:mode "\\.hs$"
|
||||
:mode ("\\.ghci$" . ghci-script-mode)
|
||||
@ -30,8 +38,3 @@
|
||||
|
||||
(setq company-ghc-show-info 'oneline))
|
||||
|
||||
|
||||
;;
|
||||
(if (featurep! +dante)
|
||||
(load! +dante)
|
||||
(load! +intero))
|
||||
|
58
modules/lang/java/+eclim.el
Normal file
58
modules/lang/java/+eclim.el
Normal file
@ -0,0 +1,58 @@
|
||||
;;; lang/java/+eclim.el -*- lexical-binding: t; -*-
|
||||
|
||||
;; NOTE This submodule is incomplete
|
||||
|
||||
(def-package! eclim
|
||||
:init
|
||||
(add-hook 'java-mode-hook #'eclim-mode)
|
||||
:config
|
||||
(set! :jump 'java-mode
|
||||
:definition #'eclim-java-find-declaration
|
||||
:references #'eclim-java-find-references
|
||||
:documentation #'eclim-java-show-documentation-for-current-element)
|
||||
|
||||
(require 'eclimd)
|
||||
(setq help-at-pt-display-when-idle t
|
||||
help-at-pt-timer-delay 0.1)
|
||||
(help-at-pt-set-timer)
|
||||
|
||||
;;
|
||||
(def-menu! +java/refactor-menu
|
||||
"Refactoring commands for `java-mode' buffers."
|
||||
'(("Generate constructor" :exec eclim-java-constructor)
|
||||
("Generate getter & setter" :exec eclim-java-generate-getter-and-setter)
|
||||
("Organize imports" :exec eclim-java-import-organize)
|
||||
("Reformat" :exec eclim-java-format)
|
||||
("Rename symbol at point" :exec eclim-java-refactor-rename-symbol-at-point :region nil)))
|
||||
|
||||
(def-menu! +java/help-menu
|
||||
"Help and information commands for `java-mode' buffers."
|
||||
'(("Find documentation for current element" :exec eclim-java-show-documentation-for-current-element)
|
||||
("Find references" :exec eclim-java-find-references)
|
||||
("View call hierarchy" :exec eclim-java-call-hierarchy)
|
||||
("View hierarchy" :exec eclim-java-hierarchy)
|
||||
("View problems" :exec eclim-problems)))
|
||||
|
||||
(def-menu! +java/project-menu
|
||||
"Building/compilation commands for `java-mode' buffers."
|
||||
'(("Build project" :exec eclim-project-build)
|
||||
("Create project" :exec eclim-project-create)
|
||||
("Delete project" :exec eclim-project-delete)
|
||||
("Go to project" :exec eclim-project-goto)
|
||||
("Import project" :exec eclim-project-import)
|
||||
("Close project" :exec eclim-project-close)
|
||||
("Open project" :exec eclim-project-open)
|
||||
("Update project" :exec eclim-project-update)))
|
||||
|
||||
(map! :map java-mode-map
|
||||
:localleader
|
||||
:nv "r" #'+java/refactor-menu
|
||||
:nv "c" #'+java/compile-menu
|
||||
:nv "p" #'+java/project-menu))
|
||||
|
||||
|
||||
(def-package! company-emacs-eclim
|
||||
:when (featurep! :completion company)
|
||||
:after java
|
||||
:config
|
||||
(set! :company-backend 'java-mode '(company-emacs-eclim)))
|
46
modules/lang/java/+meghanada.el
Normal file
46
modules/lang/java/+meghanada.el
Normal file
@ -0,0 +1,46 @@
|
||||
;;; lang/java/+meghanada.el -*- lexical-binding: t; -*-
|
||||
|
||||
(def-package! meghanada
|
||||
:commands meghanada-mode
|
||||
:config
|
||||
(setq meghanada-server-install-dir (concat doom-etc-dir "meghanada-server/")
|
||||
meghanada-use-company (featurep! :completion company)
|
||||
meghanada-use-flycheck (featurep! :feature syntax-checker)
|
||||
meghanada-use-eldoc t
|
||||
meghanada-use-auto-start t)
|
||||
|
||||
(add-hook 'java-mode-hook #'(rainbow-delimiters-mode eldoc-mode))
|
||||
|
||||
;; Setup on first use
|
||||
(meghanada-install-server)
|
||||
(if (file-exists-p (meghanada--locate-server-jar))
|
||||
(add-hook! 'java-mode-hook #'(meghanada-mode flycheck-mode))
|
||||
(warn "java-mode: meghanada-server not installed, java-mode will run with reduced functionality"))
|
||||
|
||||
(set! :jump 'java-mode
|
||||
:definition #'meghanada-jump-declaration
|
||||
:references #'meghanada-reference)
|
||||
|
||||
;;
|
||||
(def-menu! +java/refactor-menu
|
||||
"Refactoring commands for `java-mode' buffers."
|
||||
'(("Add imports for unqualified classes" :exec meghanada-import-all)
|
||||
("Optimize and clean up imports" :exec meghanada-optimize-import)
|
||||
("Introduce local variable" :exec meghanada-local-variable)
|
||||
("Format buffer code" :exec meghanada-code-beautify)))
|
||||
|
||||
(def-menu! +java/help-menu
|
||||
"Help and information commands for `java-mode' buffers."
|
||||
'(("Find usages" :exec meghanada-reference)
|
||||
("Show type hierarchives and implemented interfaces" :exec meghanada-typeinfo)))
|
||||
|
||||
(def-menu! +java/project-menu
|
||||
"Project commands for `java-mode' buffers."
|
||||
'(("Compile current file" :exec meghanada-compile-file)
|
||||
("Compile project" :exec meghanada-compile-project)))
|
||||
|
||||
(map! :map java-mode-map
|
||||
:localleader
|
||||
:nv "r" #'+java/refactor-menu
|
||||
:nv "c" #'+java/compile-menu
|
||||
:nv "p" #'+java/project-menu))
|
@ -1,29 +1,14 @@
|
||||
;;; lang/java/config.el -*- lexical-binding: t; -*-
|
||||
|
||||
(def-package! meghanada
|
||||
:commands meghanada-mode
|
||||
:config
|
||||
(setq meghanada-server-install-dir (concat doom-etc-dir "meghanada-server/")
|
||||
meghanada-use-company (featurep! :completion company)
|
||||
meghanada-use-flycheck (featurep! :feature syntax-checker)
|
||||
meghanada-use-eldoc t
|
||||
meghanada-use-auto-start t)
|
||||
(cond ((featurep! +meghanada) (load! +meghanada))
|
||||
((featurep! +eclim) ; FIXME lang/java +eclim
|
||||
;;(load! +eclim)
|
||||
(warn "java-mode: eclim support isn't implemented yet")))
|
||||
|
||||
;; Setup on first use
|
||||
(meghanada-install-server)
|
||||
(if (file-exists-p (meghanada--locate-server-jar))
|
||||
(add-hook! 'java-mode-hook #'(meghanada-mode flycheck-mode))
|
||||
(warn "java-mode: meghanada-server not installed, java-mode will run with reduced functionality"))
|
||||
|
||||
(add-hook 'java-mode-hook #'(rainbow-delimiters-mode eldoc-mode))
|
||||
|
||||
(set! :build 'compile-file 'java-mode #'meghanada-compile-file)
|
||||
(set! :build 'compile-project 'java-mode #'meghanada-compile-project)
|
||||
|
||||
(set! :jump 'java-mode :definition #'meghanada-jump-declaration)
|
||||
|
||||
(map! :map meghanada-mode-map :m "gd" #'meghanada-jump-declaration))
|
||||
|
||||
;;
|
||||
;; Common plugins
|
||||
;;
|
||||
|
||||
(def-package! android-mode
|
||||
:commands android-mode
|
||||
|
@ -1,7 +1,14 @@
|
||||
;; -*- no-byte-compile: t; -*-
|
||||
;;; lang/java/packages.el
|
||||
|
||||
(package! meghanada)
|
||||
(package! android-mode)
|
||||
(package! groovy-mode)
|
||||
|
||||
(when (featurep! +meghanada)
|
||||
(package! meghanada))
|
||||
|
||||
(when (featurep! +eclim)
|
||||
(package! eclim)
|
||||
(when (featurep! :completion company)
|
||||
(package! company-emacs-eclim)))
|
||||
|
||||
|
@ -169,7 +169,6 @@
|
||||
|
||||
(defun +javascript|init-screeps-mode ()
|
||||
(when (eq major-mode 'js2-mode)
|
||||
(cl-pushnew 'javascript-jshint flycheck-disabled-checkers)
|
||||
(push 'javascript-jshint flycheck-disabled-checkers)
|
||||
(setq js2-additional-externs (append '("_") screeps-objects screeps-constants))))
|
||||
(add-hook '+javascript-screeps-mode-hook #'+javascript|init-screeps-mode)
|
||||
|
||||
|
@ -18,50 +18,29 @@
|
||||
;; Conform switch-case indentation to editorconfig's config
|
||||
(set! :editorconfig :add '(js2-mode js2-basic-offset js-switch-indent-offset))
|
||||
|
||||
;; Favor local eslint over global, if available
|
||||
(defun +javascript|init-flycheck-elint ()
|
||||
(when (derived-mode-p 'js-mode)
|
||||
(when-let ((eslint (expand-file-name "node_modules/eslint/bin/eslint.js"
|
||||
(doom-project-root)))
|
||||
(exists-p (file-exists-p eslint))
|
||||
(executable-p (file-executable-p eslint)))
|
||||
(setq-local flycheck-javascript-eslint-executable eslint))))
|
||||
(add-hook 'flycheck-mode-hook #'+javascript|init-flycheck-elint)
|
||||
|
||||
(sp-with-modes '(js2-mode rjsx-mode)
|
||||
(sp-local-pair "/* " " */" :post-handlers '(("| " "SPC"))))
|
||||
|
||||
;; If it's available globally, use eslint_d
|
||||
(setq flycheck-javascript-eslint-executable (executable-find "eslint_d"))
|
||||
|
||||
(defun +javascript|init-flycheck-eslint ()
|
||||
"Favor local eslint over global installs and configure flycheck for eslint."
|
||||
(when (derived-mode-p 'js-mode)
|
||||
(when-let ((exec-path (list (doom-project-expand "node_modules/.bin")))
|
||||
(eslint (executable-find "eslint")))
|
||||
(setq-local flycheck-javascript-eslint-executable eslint))
|
||||
(when (flycheck-find-checker-executable 'javascript-eslint)
|
||||
;; Flycheck has it's own trailing command and semicolon warning that was
|
||||
;; conflicting with the eslint settings.
|
||||
(setq-local js2-strict-trailing-comma-warning nil)
|
||||
(setq-local js2-strict-missing-semi-warning nil))))
|
||||
(add-hook 'flycheck-mode-hook #'+javascript|init-flycheck-eslint)
|
||||
|
||||
(map! :map js2-mode-map
|
||||
:localleader
|
||||
:n "S" #'+javascript/skewer-this-buffer
|
||||
|
||||
:prefix "r"
|
||||
:n "g" #'js2r-add-to-globals-annotation
|
||||
:n "ca" #'js2r-arguments-to-object
|
||||
:n "Xa" #'js2r-contract-array
|
||||
:n "Xf" #'js2r-contract-function
|
||||
:n "Xo" #'js2r-contract-object
|
||||
:nv "d" #'js2r-debug-this
|
||||
:n "xa" #'js2r-expand-array
|
||||
:n "xf" #'js2r-expand-function
|
||||
:n "xo" #'js2r-expand-object
|
||||
:v "ef" #'js2r-extract-function
|
||||
:v "em" #'js2r-extract-method
|
||||
:v "ev" #'js2r-extract-var
|
||||
:n "F" #'js2r-forward-barf
|
||||
:n "f" #'js2r-forward-slurp
|
||||
:v "ii" #'js2r-inject-global-in-iife
|
||||
:v "iv" #'js2r-inline-var
|
||||
:v "p" #'js2r-introduce-parameter
|
||||
:n "p" #'js2r-localize-parameter
|
||||
:nv "l" #'js2r-log-this
|
||||
:n "r" #'js2r-rename-var
|
||||
:n "ss" #'js2r-split-string
|
||||
:n "sv" #'js2r-split-var-declaration
|
||||
:n "ct" #'js2r-ternary-to-if
|
||||
:v "u" #'js2r-unwrap
|
||||
:n "t" #'js2r-var-to-this
|
||||
:n "ii" #'js2r-wrap-buffer-in-iife))
|
||||
"r" #'+javascript/refactor-menu
|
||||
"S" #'+javascript/skewer-this-buffer))
|
||||
|
||||
|
||||
;; A find-{definition,references} backend for js2-mode. NOTE The xref API is
|
||||
@ -81,14 +60,43 @@
|
||||
js2r-add-to-globals-annotation js2r-extract-var js2r-inline-var
|
||||
js2r-rename-var js2r-var-to-this js2r-arguments-to-object js2r-ternary-to-if
|
||||
js2r-split-var-declaration js2r-split-string js2r-unwrap js2r-log-this
|
||||
js2r-debug-this js2r-forward-slurp js2r-forward-barf))
|
||||
js2r-debug-this js2r-forward-slurp js2r-forward-barf)
|
||||
:init
|
||||
(def-menu! +javascript/refactor-menu
|
||||
"Refactoring commands for `js2-mode' buffers."
|
||||
'(("Extract into function" :exec js2r-extract-function :region t)
|
||||
("Extract into method" :exec js2r-extract-method :region t)
|
||||
("Introduce parameter to function" :exec js2r-introduce-parameter :region t)
|
||||
("Localize parameter" :exec js2r-localize-parameter :region nil)
|
||||
("Expand object" :exec js2r-expand-object :region nil)
|
||||
("Expand function" :exec js2r-expand-function :region nil)
|
||||
("Expand array" :exec js2r-expand-array :region nil)
|
||||
("Contract object" :exec js2r-contract-object :region nil)
|
||||
("Contract function" :exec js2r-contract-function :region nil)
|
||||
("Contract array" :exec js2r-contract-array :region nil)
|
||||
("Wrap buffer in IIFE" :exec js2r-wrap-buffer-in-iife :region nil)
|
||||
("Inject global into IIFE" :exec js2r-inject-global-in-iife :region t)
|
||||
("Add to globals annotation" :exec js2r-add-to-globals-annotation :region nil)
|
||||
("Extract variable" :exec js2r-extract-var :region t)
|
||||
("Inline variable" :exec js2r-inline-var :region t)
|
||||
("Rename variable" :exec js2r-rename-var :region nil)
|
||||
("Replace var with this" :exec js2r-var-to-this :region nil)
|
||||
("Arguments to object" :exec js2r-arguments-to-object :region nil)
|
||||
("Ternary to if" :exec js2r-ternary-to-if :region nil)
|
||||
("Split var declaration" :exec js2r-split-var-declaration :region nil)
|
||||
("Split string" :exec js2r-split-string :region nil)
|
||||
("Unwrap" :exec js2r-unwrap :region t)
|
||||
("Log this" :exec js2r-log-this)
|
||||
("Debug this" :exec js2r-debug-this)
|
||||
("Reformat buffer (eslint_d)" :exec eslintd-fix :region nil :when (fboundp 'eslintd-fix)))
|
||||
:prompt "Refactor: "))
|
||||
|
||||
|
||||
(def-package! tern
|
||||
:commands tern-mode
|
||||
:init (add-hook 'js2-mode-hook #'tern-mode)
|
||||
:config
|
||||
(advice-add #'tern-project-dir :override #'doom*project-root))
|
||||
(advice-add #'tern-project-dir :override #'doom-project-root))
|
||||
|
||||
|
||||
(def-package! company-tern
|
||||
@ -103,17 +111,15 @@
|
||||
:mode "\\.jsx$"
|
||||
:mode "components/.+\\.js$"
|
||||
:init
|
||||
;; auto-detect JSX file
|
||||
(push (cons (lambda ()
|
||||
(defun +javascript-jsx-file-p ()
|
||||
(and buffer-file-name
|
||||
(equal (file-name-extension buffer-file-name) "js")
|
||||
(re-search-forward "\\(^\\s-*import React\\|\\( from \\|require(\\)[\"']react\\)"
|
||||
magic-mode-regexp-match-limit t)
|
||||
(progn
|
||||
(goto-char (match-beginning 1))
|
||||
(progn (goto-char (match-beginning 1))
|
||||
(not (sp-point-in-string-or-comment)))))
|
||||
'rjsx-mode)
|
||||
magic-mode-alist)
|
||||
|
||||
(push (cons #'+javascript-jsx-file-p 'rjsx-mode) magic-mode-alist)
|
||||
|
||||
:config
|
||||
(set! :electric 'rjsx-mode :chars '(?\} ?\) ?. ?>))
|
||||
@ -138,6 +144,10 @@
|
||||
(map! :map* (json-mode js2-mode-map) :n "gQ" #'web-beautify-js))
|
||||
|
||||
|
||||
(def-package! eslintd-fix
|
||||
:commands (eslintd-fix-mode eslintd-fix))
|
||||
|
||||
|
||||
;;
|
||||
;; Skewer-mode
|
||||
;;
|
||||
@ -174,28 +184,27 @@
|
||||
;;
|
||||
|
||||
(def-project-mode! +javascript-screeps-mode
|
||||
:match "/screeps/.+$"
|
||||
:match "/screeps\\(-ai\\)?/.+$"
|
||||
:modes (+javascript-npm-mode)
|
||||
:init (load! +screeps))
|
||||
:add-hooks (+javascript|init-screeps-mode)
|
||||
:on-load (load! +screeps))
|
||||
|
||||
(def-project-mode! +javascript-gulp-mode
|
||||
:files "gulpfile.js")
|
||||
|
||||
(def-project-mode! +javascript-npm-mode
|
||||
:modes (html-mode css-mode web-mode js2-mode markdown-mode)
|
||||
:files "package.json")
|
||||
:files "package.json"
|
||||
:on-enter
|
||||
(when (make-local-variable 'exec-path)
|
||||
(push (doom-project-expand "node_modules/.bin")
|
||||
exec-path)))
|
||||
|
||||
(def-project-mode! +javascript-lb6-mode
|
||||
:modes (web-mode js2-mode nxml-mode markdown-mode)
|
||||
:match "\\.lb\\(action\\|ext\\)/"
|
||||
:init
|
||||
;; TODO
|
||||
;; (when IS-MAC
|
||||
;; (set! :build 'launchbar-action '+javascript-lb6-mode
|
||||
;; (lambda ()
|
||||
;; (when-let (dir (f-traverse-upwards (lambda (f) (f-ext? f "lbaction"))))
|
||||
;; (shell-command (format "open '%s'" dir))))
|
||||
;; :when
|
||||
;; (lambda () (f-traverse-upwards (lambda (f) (f-ext? f "lbaction"))))))
|
||||
)
|
||||
|
||||
;;
|
||||
;; Tools
|
||||
;;
|
||||
|
||||
(def-project-mode! +javascript-eslintd-fix-mode
|
||||
:add-hooks (eslintd-fix-mode))
|
||||
|
||||
|
@ -11,6 +11,7 @@
|
||||
(package! tern)
|
||||
(package! web-beautify)
|
||||
(package! skewer-mode)
|
||||
(package! eslintd-fix)
|
||||
|
||||
(when (featurep! :completion company)
|
||||
(package! company-tern))
|
||||
|
@ -3,15 +3,13 @@
|
||||
(def-package! ledger-mode
|
||||
:mode "\\.ledger$"
|
||||
:commands ledger-mode
|
||||
:config
|
||||
(setq ledger-clear-whole-transactions 1))
|
||||
:config (setq ledger-clear-whole-transactions 1))
|
||||
|
||||
|
||||
(def-package! evil-ledger
|
||||
:when (featurep! :feature evil)
|
||||
:after ledger-mode
|
||||
:config
|
||||
(add-hook 'ledger-mode-hook #'evil-ledger-mode))
|
||||
:config (add-hook 'ledger-mode-hook #'evil-ledger-mode))
|
||||
|
||||
|
||||
(def-package! flycheck-ledger
|
||||
|
@ -7,3 +7,13 @@
|
||||
(lua-start-process "lua" "lua")
|
||||
(pop-to-buffer lua-process-buffer))
|
||||
|
||||
;;;###autoload
|
||||
(defun +lua/run-love-game ()
|
||||
"Run the current project with Love2D."
|
||||
(interactive)
|
||||
(async-shell-command
|
||||
(format "%s %s"
|
||||
(or (executable-find "love")
|
||||
(if IS-MAC "open -a love.app"))
|
||||
(shell-quote-argument (doom-project-root)))))
|
||||
|
||||
|
@ -10,7 +10,16 @@
|
||||
(set! :repl 'lua-mode #'+lua/repl)
|
||||
|
||||
;; sp's lua-specific rules are obnoxious, so we disable them
|
||||
(setq sp-pairs (delete (assq 'lua-mode sp-pairs) sp-pairs)))
|
||||
(setq sp-pairs (delete (assq 'lua-mode sp-pairs) sp-pairs))
|
||||
|
||||
(def-menu! +lua/build-menu
|
||||
"Build/compilation commands for `lua-mode' buffers."
|
||||
'(("Run Love app" :exec +lua/run-love-game :when +lua-love-mode))
|
||||
:prompt "Build tasks: ")
|
||||
|
||||
(map! :map lua-mode-map
|
||||
:localleader
|
||||
"b" #'+lua/build-menu))
|
||||
|
||||
|
||||
(def-package! company-lua
|
||||
@ -32,9 +41,5 @@
|
||||
|
||||
(def-project-mode! +lua-love-mode
|
||||
:modes (lua-mode markdown-mode json-mode)
|
||||
:files (and "main.lua" "conf.lua")
|
||||
:init
|
||||
(set! :build 'run-love-app '+lua-love-mode
|
||||
(lambda ()
|
||||
(async-shell-command (format "open -a love.app '%s'" (doom-project-root))))))
|
||||
:files (and "main.lua" "conf.lua"))
|
||||
|
||||
|
@ -37,7 +37,7 @@
|
||||
:m "]p" #'markdown-demote
|
||||
:m "[l" #'markdown-next-link
|
||||
:m "]l" #'markdown-previous-link
|
||||
:i "M--" #'markdown-insert-hr)
|
||||
:i "M--" #'markdown-insert-hr
|
||||
|
||||
(:localleader
|
||||
:nv "o" #'markdown-open
|
||||
@ -45,7 +45,7 @@
|
||||
(:prefix "i"
|
||||
:nv "t" #'markdown-toc-generate-toc
|
||||
:nv "i" #'markdown-insert-image
|
||||
:nv "l" #'markdown-insert-link))))
|
||||
:nv "l" #'markdown-insert-link)))))
|
||||
|
||||
|
||||
(def-package! markdown-toc
|
||||
|
@ -1,5 +1,20 @@
|
||||
;;; lang/python/config.el -*- lexical-binding: t; -*-
|
||||
|
||||
(defvar +python-pyenv-root nil
|
||||
"The path to pyenv's root directory. This is automatically set when `python'
|
||||
is loaded.")
|
||||
|
||||
(defvar +python-pyenv-versions nil
|
||||
"Available versions of python in pyenv.")
|
||||
|
||||
(defvar-local +python-current-version nil
|
||||
"The currently active pyenv version.")
|
||||
|
||||
|
||||
;;
|
||||
;; Plugins
|
||||
;;
|
||||
|
||||
(def-package! python
|
||||
:commands python-mode
|
||||
:init
|
||||
@ -24,6 +39,33 @@
|
||||
python-shell-completion-string-code
|
||||
"';'.join(get_ipython().Completer.all_completions('''%s'''))\n"))
|
||||
|
||||
;; Version management with pyenv
|
||||
(defun +python|add-version-to-modeline ()
|
||||
"Add version string to the major mode in the modeline."
|
||||
(setq mode-name
|
||||
(if +python-current-version
|
||||
(format "Python %s" +python-current-version)
|
||||
"Python")))
|
||||
(add-hook 'python-mode-hook #'+python|add-version-to-modeline)
|
||||
|
||||
(if (not (executable-find "pyenv"))
|
||||
(setq +python-current-version (string-trim (shell-command-to-string "python --version 2>&1 | cut -d' ' -f2")))
|
||||
(setq +python-pyenv-root (string-trim (shell-command-to-string "pyenv root"))
|
||||
+python-pyenv-versions (split-string (shell-command-to-string "pyenv versions --bare") "\n" t))
|
||||
|
||||
(defun +python|detect-pyenv-version ()
|
||||
"Detect the pyenv version for the current project and set the relevant
|
||||
environment variables."
|
||||
(when-let (version-str (shell-command-to-string "python --version 2>&1 | cut -d' ' -f2"))
|
||||
(setq version-str (string-trim version-str)
|
||||
+python-current-version version-str)
|
||||
(let ((pyenv-current-path (concat +python-pyenv-root "/versions/" version-str)))
|
||||
(when (file-directory-p pyenv-current-path)
|
||||
(setq pythonic-environment pyenv-current-path)))
|
||||
(when (member version-str +python-pyenv-versions)
|
||||
(setenv "PYENV_VERSION" version-str))))
|
||||
(add-hook 'python-mode-hook #'+python|detect-pyenv-version))
|
||||
|
||||
(define-key python-mode-map (kbd "DEL") nil) ; interferes with smartparens
|
||||
(sp-with-modes 'python-mode
|
||||
(sp-local-pair "'" nil :unless '(sp-point-before-word-p sp-point-after-word-p sp-point-before-same-p))))
|
||||
|
@ -1,5 +1,16 @@
|
||||
;;; lang/ruby/config.el -*- lexical-binding: t; -*-
|
||||
|
||||
(defvar +ruby-rbenv-versions nil
|
||||
"Available versions of ruby in rbenv.")
|
||||
|
||||
(defvar-local +ruby-current-version nil
|
||||
"The currently active ruby version.")
|
||||
|
||||
|
||||
;;
|
||||
;; Plugins
|
||||
;;
|
||||
|
||||
(def-package! ruby-mode
|
||||
:mode ("\\.rb$" "\\.rake$" "\\.gemspec$" "\\.?pryrc$"
|
||||
"/\\(Gem\\|Cap\\|Vagrant\\|Rake\\|Pod\\|Puppet\\|Berks\\)file$")
|
||||
@ -13,6 +24,29 @@
|
||||
;; Don't interfere with my custom RET behavior
|
||||
(define-key ruby-mode-map [?\n] nil)
|
||||
|
||||
;; Version management with rbenv
|
||||
(defun +ruby|add-version-to-modeline ()
|
||||
"Add version string to the major mode in the modeline."
|
||||
(setq mode-name
|
||||
(if +python-current-version
|
||||
(format "Ruby %s" +ruby-current-version)
|
||||
"Ruby")))
|
||||
(add-hook 'ruby-mode-hook #'+ruby|add-version-to-modeline)
|
||||
|
||||
(if (not (executable-find "rbenv"))
|
||||
(setq +ruby-current-version (string-trim (shell-command-to-string "ruby --version 2>&1 | cut -d' ' -f2")))
|
||||
(setq +ruby-rbenv-versions (split-string (shell-command-to-string "rbenv versions --bare") "\n" t))
|
||||
|
||||
(defun +ruby|detect-rbenv-version ()
|
||||
"Detect the rbenv version for the current project and set the relevant
|
||||
environment variables."
|
||||
(when-let (version-str (shell-command-to-string "ruby --version 2>&1 | cut -d' ' -f2"))
|
||||
(setq version-str (string-trim version-str)
|
||||
+ruby-current-version version-str)
|
||||
(when (member version-str +ruby-rbenv-versions)
|
||||
(setenv "RBENV_VERSION" version-str))))
|
||||
(add-hook 'ruby-mode-hook #'+ruby|detect-rbenv-version))
|
||||
|
||||
(map! :map ruby-mode-map
|
||||
:localleader
|
||||
:prefix "r"
|
||||
@ -72,12 +106,7 @@
|
||||
:config (set! :company-backend 'inf-ruby-mode '(company-inf-ruby)))
|
||||
|
||||
|
||||
;;
|
||||
;; TODO Frameworks
|
||||
;;
|
||||
(def-package! rake
|
||||
:commands (rake rake-find-task rake-rerun)
|
||||
:config (setq rake-completion-system 'default))
|
||||
|
||||
;; (def-project-mode! +ruby-rake-mode
|
||||
;; :files "Rakefile"
|
||||
;; :init
|
||||
;; (set! :build 'rake '+ruby-rake-mode '+ruby/rake
|
||||
;; :when (lambda () (doom-project-has! "Rakefile"))))
|
||||
|
@ -7,6 +7,7 @@
|
||||
(package! rspec-mode)
|
||||
(package! ruby-refactor)
|
||||
(package! yard-mode)
|
||||
(package! rake)
|
||||
|
||||
(when (featurep! :completion company)
|
||||
(package! company-inf-ruby))
|
||||
|
@ -2,4 +2,7 @@
|
||||
|
||||
;; TODO (defun +rust/run-cargo () (interactive))
|
||||
|
||||
;; TODO (defun +rust-cargo-project-p ())
|
||||
;;;###autoload
|
||||
(defun +rust-cargo-project-p ()
|
||||
"Return t if this is a cargo project."
|
||||
(doom-project-has! "Cargo.toml"))
|
||||
|
@ -1,15 +1,21 @@
|
||||
;;; lang/rust/config.el -*- lexical-binding: t; -*-
|
||||
|
||||
(defvar +rust-ext-dir (concat doom-etc-dir "rust/")
|
||||
"TODO")
|
||||
(defvar +rust-src-dir (concat doom-etc-dir "rust/")
|
||||
"The path to Rust source library. Required by racer.")
|
||||
|
||||
|
||||
;;
|
||||
;; Plugins
|
||||
;;
|
||||
|
||||
(def-package! rust-mode
|
||||
:mode "\\.rs$"
|
||||
:init
|
||||
(add-hook 'rust-mode-hook #'flycheck-mode)
|
||||
:config
|
||||
(set! :build 'run-cargo '(rust-mode toml-mode) #'+rust/run-cargo
|
||||
:when #'+rust-cargo-project-p))
|
||||
(def-menu! +rust/build-menu
|
||||
"TODO"
|
||||
'(("run" :exec "cargo run" :cwd t :when (+rust-cargo-project-p))
|
||||
("build" :exec "cargo build" :cwd t :when (+rust-cargo-project-p)))
|
||||
:prompt "Cargo: "))
|
||||
|
||||
|
||||
(def-package! racer
|
||||
@ -18,14 +24,13 @@
|
||||
:init
|
||||
(add-hook! 'rust-mode-hook #'(racer-mode eldoc-mode flycheck-rust-setup))
|
||||
:config
|
||||
(setq racer-cmd (expand-file-name "racer/target/release/racer" +rust-ext-dir)
|
||||
racer-rust-src-path (expand-file-name "rust/src/" +rust-ext-dir))
|
||||
(setq racer-cmd (expand-file-name "racer/target/release/racer" +rust-src-dir)
|
||||
racer-rust-src-path (expand-file-name "rust/src/" +rust-src-dir))
|
||||
|
||||
(set! :jump 'rust-mode :definition #'racer-find-definition)
|
||||
|
||||
(unless (file-exists-p racer-cmd)
|
||||
(warn "rust-mode: racer binary can't be found; auto-completion is disabled"))
|
||||
|
||||
;; TODO Unit test keybinds
|
||||
(map! :map rust-mode-map :m "gd" #'racer-find-definition))
|
||||
(warn "rust-mode: racer binary can't be found; auto-completion is disabled")))
|
||||
|
||||
|
||||
(def-package! company-racer
|
||||
@ -36,5 +41,6 @@
|
||||
|
||||
(def-package! flycheck-rust
|
||||
:when (featurep! :feature syntax-checker)
|
||||
:after rust-mode)
|
||||
:after rust-mode
|
||||
:config (add-hook 'rust-mode-hook #'flycheck-mode))
|
||||
|
||||
|
@ -14,6 +14,7 @@
|
||||
|
||||
(def-package! sh-script ; built-in
|
||||
:mode ("\\.zsh$" . sh-mode)
|
||||
:mode ("\\.zunit$" . sh-mode)
|
||||
:mode ("/bspwmrc$" . sh-mode)
|
||||
:init
|
||||
(add-hook! sh-mode #'(flycheck-mode highlight-numbers-mode))
|
||||
|
@ -16,9 +16,7 @@
|
||||
;; '(tide-jump-to-definition "jump to definition")
|
||||
;; '(tide-documentation-at-point "current type documentation")
|
||||
;; '(tide-restart-server "restart tide server"))
|
||||
|
||||
(map! :localleader
|
||||
:m "fh" #'tide-documentation-at-point))
|
||||
)
|
||||
|
||||
|
||||
(def-package! tide
|
||||
@ -41,8 +39,7 @@
|
||||
(equal (file-name-extension buffer-file-name) "tsx")))
|
||||
(tide-setup)
|
||||
(flycheck-mode +1)
|
||||
(eldoc-mode +1)))
|
||||
(add-hook! (typescript-mode web-mode) #'+typescript|init-tide)
|
||||
|
||||
(advice-add #'tide-project-root :override #'doom*project-root))
|
||||
(eldoc-mode +1)
|
||||
(setq tide-project-root (doom-project-root))))
|
||||
(add-hook! (typescript-mode web-mode) #'+typescript|init-tide))
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
(:localleader
|
||||
:n "rb" #'+css/toggle-inline-or-block))
|
||||
|
||||
|
||||
;;
|
||||
;; Packages
|
||||
;;
|
||||
@ -36,15 +37,14 @@
|
||||
:mode ("\\.scss$" . scss-mode)
|
||||
:config
|
||||
(set! :company-backend '(css-mode scss-mode) '(company-css company-yasnippet))
|
||||
(set! :build 'compile-to-css 'scss-mode #'+css/scss-build))
|
||||
(map! :map scss-mode-map :localleader "b" #'+css/scss-build))
|
||||
|
||||
|
||||
(def-package! sass-mode
|
||||
:mode "\\.sass$"
|
||||
:config
|
||||
(setq sass-command-options '("--style compressed"))
|
||||
(set! :company-backend 'sass-mode '(company-css company-yasnippet))
|
||||
(set! :build 'compile-to-css 'sass-mode #'+css/sass-build))
|
||||
(map! :map scss-mode-map :localleader "b" #'+css/sass-build))
|
||||
|
||||
|
||||
(def-package! less-css-mode
|
||||
|
@ -41,7 +41,4 @@
|
||||
:mode "\\.jade$"
|
||||
:mode "\\.pug$"
|
||||
:config
|
||||
(set! :company-backend 'pug-mode '(company-yasnippet))
|
||||
(map! :map pug-mode-map
|
||||
:i [tab] #'doom/dumb-indent
|
||||
:i [backtab] #'doom/dumb-dedent))
|
||||
(set! :company-backend 'pug-mode '(company-yasnippet)))
|
||||
|
@ -1,6 +1,5 @@
|
||||
;;; lang/web/autoload/html.el -*- lexical-binding: t; -*-
|
||||
|
||||
;;;###autoload
|
||||
(defvar +web-entities-list
|
||||
[[" " " "] [" " " "] [" " " "] [" " " "]
|
||||
["‏" ""] ["‎" ""] ["‍" ""] ["‌" ""]
|
||||
|
@ -38,11 +38,9 @@
|
||||
(def-project-mode! +web-jekyll-mode
|
||||
:modes (web-mode js-mode coffee-mode css-mode haml-mode pug-mode)
|
||||
:files (and "config.yml" (or "_layouts/" "_posts/"))
|
||||
:init
|
||||
(defun +web|init-jekyll-mode ()
|
||||
:on-enter
|
||||
(when (eq major-mode 'web-mode)
|
||||
(web-mode-set-engine "django")))
|
||||
(add-hook '+web-jekyll-mode-hook #'+web|init-jekyll-mode))
|
||||
|
||||
(def-project-mode! +web-wordpress-mode
|
||||
:modes (php-mode web-mode css-mode haml-mode pug-mode)
|
||||
|
@ -9,11 +9,12 @@
|
||||
(package! counsel-css :recipe (:fetcher github :repo "hlissner/emacs-counsel-css")))
|
||||
|
||||
;; +html.el
|
||||
(package! company-web)
|
||||
(package! emmet-mode)
|
||||
(package! haml-mode)
|
||||
(package! pug-mode)
|
||||
(package! web-mode)
|
||||
(when (featurep! :completion company)
|
||||
(package! company-web))
|
||||
|
||||
;; +css.el
|
||||
(package! less-css-mode)
|
||||
|
@ -91,7 +91,7 @@ the cursor."
|
||||
(or ext (file-name-extension filename))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +org-attach*insert-link (link filename)
|
||||
(defun +org-attach*insert-link (_link filename)
|
||||
"TODO"
|
||||
(if (looking-back "^[ \t]+" (line-beginning-position))
|
||||
(delete-region (match-beginning 0) (match-end 0))
|
||||
|
@ -1,10 +1,10 @@
|
||||
;;; org/org-capture/autoload/evil.el -*- lexical-binding: t; -*-
|
||||
|
||||
;;;###autoload (autoload '+org-capture:dwim "org/org-capture/autoload/evil" nil t)
|
||||
(evil-define-operator +org-capture:dwim (&optional beg end)
|
||||
;;;###autoload (autoload '+org-capture:open "org/org-capture/autoload/evil" nil t)
|
||||
(evil-define-operator +org-capture:open (&optional beg end)
|
||||
"Evil ex interface to `+org-capture/dwim'."
|
||||
:move-point nil :type inclusive
|
||||
(interactive "<r>")
|
||||
(+org-capture/dwim
|
||||
(+org-capture/open
|
||||
(unless (or (evil-normal-state-p) (evil-insert-state-p))
|
||||
(buffer-substring beg end))))
|
||||
|
@ -1,7 +1,7 @@
|
||||
;;; org/org-capture/autoload/org-capture.el -*- lexical-binding: t; -*-
|
||||
|
||||
;;;###autoload
|
||||
(defun +org-capture/dwim (&optional string key)
|
||||
(defun +org-capture/open (&optional string key)
|
||||
"Sends STRING, the current selection or prompted input to `org-capture'.
|
||||
|
||||
Uses the capture template specified by KEY. Otherwise, prompts you for one."
|
||||
@ -15,3 +15,57 @@ Uses the capture template specified by KEY. Otherwise, prompts you for one."
|
||||
(region-end)))))
|
||||
(org-capture-string string key)
|
||||
(org-capture nil key))))
|
||||
|
||||
|
||||
;; --- External frame ---------------------
|
||||
|
||||
(defvar +org-capture-window-params
|
||||
`((name . "org-capture")
|
||||
(width . 70)
|
||||
(height . 25)
|
||||
(window-system . ,(cond (IS-MAC 'ns)
|
||||
(IS-LINUX 'x)
|
||||
(t 'w32)))
|
||||
,(if IS-LINUX '(display . ":0")))
|
||||
"TODO")
|
||||
|
||||
;;;###autoload
|
||||
(defun +org-capture|cleanup-frame ()
|
||||
"Closes the org-capture frame once done adding an entry."
|
||||
(when (+org-capture-frame-p)
|
||||
(delete-frame nil t)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +org-capture-frame-p (&rest _)
|
||||
"Return t if the current frame is an org-capture frame opened by
|
||||
`+org-capture/open-frame'."
|
||||
(equal "org-capture" (frame-parameter nil 'name)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +org-capture/open-frame (&optional string key)
|
||||
"Opens the org-capture window in a floating frame that cleans itself up once
|
||||
you're done. This can be called from an external shell script."
|
||||
(interactive)
|
||||
(require 'org)
|
||||
(let (after-make-frame-functions before-make-frame-hook)
|
||||
(let ((frame (if (+org-capture-frame-p)
|
||||
(selected-frame)
|
||||
(make-frame +org-capture-window-params))))
|
||||
(with-selected-frame frame
|
||||
(condition-case ex
|
||||
(cl-letf (((symbol-function #'pop-to-buffer)
|
||||
(symbol-function #'switch-to-buffer)))
|
||||
(if (and (stringp string)
|
||||
(not (string-empty-p string)))
|
||||
(org-capture-string string key)
|
||||
(org-capture nil key))
|
||||
(when (featurep 'solaire-mode)
|
||||
(solaire-mode +1)))
|
||||
('error
|
||||
(message "org-capture: %s" (error-message-string ex))
|
||||
(delete-frame frame)))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +org-capture-available-keys ()
|
||||
"TODO"
|
||||
(string-join (mapcar #'car org-capture-templates) ""))
|
||||
|
@ -12,56 +12,21 @@
|
||||
;; anywhere I can call org-capture (whether or not Emacs is open/running),
|
||||
;; like, say, from qutebrowser, vimperator, dmenu or a global keybinding.
|
||||
|
||||
(defun +org-capture|init ()
|
||||
"Set up a sane `org-capture' workflow."
|
||||
(setq org-default-notes-file (concat +org-dir "notes.org")
|
||||
;; FIXME This is incomplete!
|
||||
org-capture-templates
|
||||
'(;; TODO: New vocabulary word
|
||||
|
||||
("t" "Todo" entry
|
||||
'(("t" "Todo" entry
|
||||
(file+headline (expand-file-name "todo.org" +org-dir) "Inbox")
|
||||
"* [ ] %?")
|
||||
|
||||
("c" "Changelog" entry
|
||||
(file+headline (expand-file-name "CHANGELOG.org" (doom-project-root)) "Unreleased")
|
||||
"* %?")
|
||||
|
||||
;; ("p" "Project Notes" entry
|
||||
;; (file+headline org-default-notes-file "Inbox")
|
||||
;; "* %u %?\n%i" :prepend t)
|
||||
|
||||
;; ("m" "Major-mode Notes" entry
|
||||
;; (file+headline org-default-notes-file "Inbox")
|
||||
;; "* %u %?\n%i" :prepend t)
|
||||
"* [ ] %?\n%i" :prepend t :kill-buffer t)
|
||||
|
||||
("n" "Notes" entry
|
||||
(file+headline (concat +org-dir "notes.org") "Inbox")
|
||||
"* %u %?\n%i" :prepend t)
|
||||
(file+headline org-default-notes-file "Inbox")
|
||||
"* %u %?\n%i" :prepend t :kill-buffer t)))
|
||||
|
||||
;; ("v" "Vocab" entry
|
||||
;; (file+headline (concat org-directory "topics/vocab.org") "Unsorted")
|
||||
;; "** %i%?\n")
|
||||
))
|
||||
(defun +org-capture|init ()
|
||||
(add-hook 'org-capture-after-finalize-hook #'+org-capture|cleanup-frame)
|
||||
|
||||
(when (featurep! :feature evil)
|
||||
(add-hook 'org-capture-mode-hook #'evil-insert-state))
|
||||
|
||||
;; Allows the Emacs mini-frame (opened from an external shell script to run
|
||||
;; and clean up properly) if the frame is named "org-capture".
|
||||
(require 'org-capture)
|
||||
(require 'org-protocol)
|
||||
(defun +org-capture*init (&rest _)
|
||||
"Makes sure the org-capture window is the only window in the frame."
|
||||
(when (equal "org-capture" (frame-parameter nil 'name))
|
||||
(setq mode-line-format nil)
|
||||
(delete-other-windows)))
|
||||
(advice-add #'org-capture :after #'+org-capture*init)
|
||||
|
||||
(defun +org-capture|finalize ()
|
||||
"Closes the frame once org-capture is done."
|
||||
(when (equal "org-capture" (frame-parameter nil 'name))
|
||||
(when (and (featurep 'persp-mode) persp-mode)
|
||||
(+workspace/delete (+workspace-current-name)))
|
||||
(delete-frame)))
|
||||
(add-hook 'org-capture-after-finalize-hook #'+org-capture|finalize))
|
||||
(when (featurep! :ui doom-dashboard)
|
||||
(add-hook '+doom-dashboard-inhibit-functions #'+org-capture-frame-p)))
|
||||
|
@ -1,36 +0,0 @@
|
||||
;;; org/org-notebook/autoload.el -*- lexical-binding: t; -*-
|
||||
|
||||
(defun +org-notebook--explore-notes (dir)
|
||||
(unless (file-directory-p dir)
|
||||
(error "Directory doesn't exist: %s" dir))
|
||||
(if (fboundp '+evil/neotree)
|
||||
(neotree-dir dir)
|
||||
(let ((default-directory dir))
|
||||
(call-interactively (command-remapping 'find-file)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +org-notebook/find-major-mode-notes ()
|
||||
"Browse org notes in `+org-notebook-code-dir' in neotree, ido, ivy or helm --
|
||||
whichever is available."
|
||||
(interactive)
|
||||
(let ((dir (expand-file-name
|
||||
(concat (or (cdr (assq major-mode +org-notebook-code-alist))
|
||||
(replace-regexp-in-string
|
||||
"+" "p"
|
||||
(string-remove-suffix "-mode" (symbol-name major-mode))
|
||||
nil t))
|
||||
"/")
|
||||
+org-notebook-code-dir)))
|
||||
(unless (file-in-directory-p dir +org-notebook-code-dir)
|
||||
(error "Invalid location for %s notes: %s"
|
||||
major-mode (abbreviate-file-name dir)))
|
||||
(unless (file-directory-p dir)
|
||||
(make-directory dir t))
|
||||
(+org-notebook--explore-notes dir)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +org-notebook/find-project-notes ()
|
||||
"Browse org notes in `+org-notebook-project-dir' in neotree, ido, ivy or helm --
|
||||
whichever is available."
|
||||
(interactive)
|
||||
(+org-notebook--explore-notes +org-notebook-project-dir))
|
@ -1,27 +0,0 @@
|
||||
;;; org/org-notebook/config.el -*- lexical-binding: t; -*-
|
||||
|
||||
;; (add-hook 'org-load-hook '+org|init-notebook t)
|
||||
|
||||
;; While I program, write or plan, I want easy access to notes of various kinds,
|
||||
;; such as major-mode/language specific notes, or project-specific notes. They
|
||||
;; can be accessed via `+org-notebook/find-major-mode-notes' and
|
||||
;; `+org-notebook/find-project-notes'.
|
||||
|
||||
(defvar +org-notebook-dir (concat +org-dir "notes/")
|
||||
"The directory where the notes are kept.")
|
||||
|
||||
(defvar +org-notebook-code-dir (concat +org-notebook-dir "code/")
|
||||
"The directory where programming notes and snippets are kept.")
|
||||
|
||||
(defvar +org-notebook-project-dir (concat +org-notebook-dir "projects/")
|
||||
"The directory where project notes are kept.")
|
||||
|
||||
|
||||
(defvar +org-notebook-code-alist
|
||||
'((js2-mode . "javascript"))
|
||||
"An alist mapping certain modes (symbols) to their org notes directory name.
|
||||
If a mode isn't here, it's guessed by stripping out the -mode suffix and
|
||||
replacing '+' characters with 'p's.")
|
||||
|
||||
|
||||
;; (defun +org|init-notebook ())
|
@ -8,8 +8,9 @@
|
||||
:group 'evil-org
|
||||
(setq org-hide-emphasis-markers +org-pretty-mode)
|
||||
(org-toggle-pretty-entities)
|
||||
(org-with-silent-modifications
|
||||
;; In case the above un-align tables
|
||||
(org-table-map-tables 'org-table-align t))
|
||||
(org-table-map-tables 'org-table-align t)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +org|realign-table-maybe ()
|
||||
@ -45,6 +46,10 @@ If on a:
|
||||
(let* ((scroll-pt (window-start))
|
||||
(context (org-element-context))
|
||||
(type (org-element-type context)))
|
||||
;; skip over unimportant contexts
|
||||
(while (and context (memq type '(verbatim code bold italic underline strike-through subscript superscript)))
|
||||
(setq context (org-element-property :parent context)
|
||||
type (org-element-type context)))
|
||||
(pcase type
|
||||
((guard (org-element-property :checkbox (org-element-lineage context '(item) t)))
|
||||
(let ((match (and (org-at-item-checkbox-p) (match-string 1))))
|
||||
@ -180,8 +185,10 @@ wrong places)."
|
||||
(- (point) (line-beginning-position)))))
|
||||
(pcase direction
|
||||
('below
|
||||
(goto-char (line-end-position))
|
||||
(insert (concat "\n" (make-string pad ? ) marker)))
|
||||
(org-end-of-item)
|
||||
(goto-char (line-beginning-position))
|
||||
(insert (make-string pad 32) (or marker ""))
|
||||
(save-excursion (insert "\n")))
|
||||
('above
|
||||
(goto-char (line-beginning-position))
|
||||
(insert (make-string pad 32) (or marker ""))
|
||||
@ -217,7 +224,6 @@ wrong places)."
|
||||
(org-back-to-heading)
|
||||
(org-insert-heading)
|
||||
(when (= level 1)
|
||||
(save-excursion (evil-open-above 1))
|
||||
(save-excursion (insert "\n")))))
|
||||
(when (org-element-property :todo-type context)
|
||||
(org-todo 'todo))))
|
||||
@ -276,3 +282,18 @@ with `org-cycle'). Also:
|
||||
(let ((window-beg (window-start)))
|
||||
(org-cycle)
|
||||
(set-window-start nil window-beg))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +org/remove-link ()
|
||||
"Unlink the text at point."
|
||||
(interactive)
|
||||
(unless (org-in-regexp org-bracket-link-regexp 1)
|
||||
(user-error "No link at point"))
|
||||
(save-excursion
|
||||
(let ((remove (list (match-beginning 0) (match-end 0)))
|
||||
(description (if (match-end 3)
|
||||
(org-match-string-no-properties 3)
|
||||
(org-match-string-no-properties 1))))
|
||||
(apply #'delete-region remove)
|
||||
(insert description))))
|
||||
|
||||
|
@ -2,7 +2,8 @@
|
||||
|
||||
;; Ensure ELPA org is prioritized above built-in org.
|
||||
(when-let (path (locate-library "org" nil doom--package-load-path))
|
||||
(cl-pushnew (file-name-directory path) load-path :test #'equal))
|
||||
(setq load-path (delete path load-path))
|
||||
(push (file-name-directory path) load-path))
|
||||
|
||||
;; Custom variables
|
||||
(defvar +org-dir (expand-file-name "~/work/org/")
|
||||
@ -55,6 +56,7 @@
|
||||
;;
|
||||
(setq line-spacing 1)
|
||||
(visual-line-mode +1)
|
||||
(org-indent-mode +1)
|
||||
(doom|disable-line-numbers)
|
||||
|
||||
;; show-paren-mode causes problems for org-indent-mode, so disable it
|
||||
@ -97,7 +99,6 @@
|
||||
org-agenda-skip-unavailable-files nil
|
||||
org-cycle-include-plain-lists t
|
||||
org-cycle-separator-lines 1
|
||||
;; org-ellipsis " "
|
||||
org-entities-user '(("flat" "\\flat" nil "" "" "266D" "♭") ("sharp" "\\sharp" nil "" "" "266F" "♯"))
|
||||
org-ellipsis " "
|
||||
org-fontify-done-headline t
|
||||
@ -113,6 +114,10 @@
|
||||
org-indent-mode-turns-on-hiding-stars t
|
||||
org-pretty-entities nil
|
||||
org-pretty-entities-include-sub-superscripts t
|
||||
org-priority-faces
|
||||
`((?a . ,(face-foreground 'error))
|
||||
(?b . ,(face-foreground 'warning))
|
||||
(?c . ,(face-foreground 'success)))
|
||||
org-startup-folded t
|
||||
org-startup-indented t
|
||||
org-startup-with-inline-images nil
|
||||
@ -143,7 +148,10 @@
|
||||
"Sets up org-mode and evil keybindings. Tries to fix the idiosyncrasies
|
||||
between the two."
|
||||
(map! (:map org-mode-map
|
||||
"RET" #'org-return-indent)
|
||||
"RET" #'org-return-indent
|
||||
"C-c C-S-l" #'+org/remove-link
|
||||
:n "j" "gj"
|
||||
:n "k" "gk")
|
||||
|
||||
(:map +org-evil-mode-map
|
||||
:n "RET" #'+org/dwim-at-point
|
||||
@ -213,9 +221,9 @@ between the two."
|
||||
|
||||
(defun +org|remove-occur-highlights ()
|
||||
"Remove org occur highlights on ESC in normal mode."
|
||||
(when (derived-mode-p 'org-mode)
|
||||
(org-remove-occur-highlights)
|
||||
t))
|
||||
(when (and (derived-mode-p 'org-mode)
|
||||
org-occur-highlights)
|
||||
(org-remove-occur-highlights)))
|
||||
(add-hook '+evil-esc-hook #'+org|remove-occur-highlights)
|
||||
|
||||
(after! recentf
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user