Merge branch 'develop' into add_shellcheck

This commit is contained in:
chrunchyjesus 2019-04-23 19:44:02 +02:00
commit e5e05f9d51
No known key found for this signature in database
GPG key ID: 0C364160C9308A88
584 changed files with 32999 additions and 15507 deletions

View file

@ -0,0 +1,9 @@
#+TITLE: :lang agda
This module adds support for the [[http://wiki.portal.chalmers.se/agda/pmwiki.php][agda]] programming language.
Emacs support is included in the agda release (you can find installation
instructions [[https://agda.readthedocs.io/en/latest/getting-started/installation.html][here]]). This module attempts to find the location of ~agda2.el~ via
the ~agda-mode locate~ command that comes with the agda release. Users can set
this manually by setting the ~+agda2-dir~ variable.

View file

@ -0,0 +1,39 @@
;;; lang/agda/config.el -*- lexical-binding: t; -*-
(defvar +agda-dir
(when (executable-find "agda-mode")
(file-name-directory (shell-command-to-string "agda-mode locate"))))
(def-package! agda2
:when +agda-dir
:load-path +agda-dir)
(def-package! agda2-mode
:defer t
:config
(map! :map agda2-mode-map
:localleader
"?" #'agda2-show-goals
"." #'agda2-goal-and-context-and-inferred
"," #'agda2-goal-and-context
"=" #'agda2-show-constraints
"SPC" #'agda2-give
"a" #'agda2-auto
"c" #'agda2-make-case
"d" #'agda2-infer-type-maybe-toplevel
"e" #'agda2-show-context
"gG" #'agda2-go-back
"h" #'agda2-helper-function-type
"l" #'agda2-load
"n" #'agda2-compute-normalised-maybe-toplevel
"p" #'agda2-module-contents-maybe-toplevel
"r" #'agda2-refine
"s" #'agda2-solveAll
"t" #'agda2-goal-type
"w" #'agda2-why-in-scope-maybe-toplevel
(:prefix "x"
"c" #'agda2-compile
"d" #'agda2-remove-annotations
"h" #'agda2-display-implicit-arguments
"q" #'agda2-quit
"r" #'agda2-restart)))

View file

@ -0,0 +1,5 @@
;; -*- lexical-binding: t; no-byte-compile: t; -*-
;;; lang/agda/doctor.el
(unless (executable-find "agda-mode")
(warn! "Couldn't find agda-mode. Agda support won't work"))

View file

@ -0,0 +1,4 @@
;;; lang/assembly/autoload.el -*- lexical-binding: t; -*-
;;;###autoload
(add-to-list 'auto-mode-alist '("\\.hax\\'" . haxor-mode))

View file

@ -1,8 +0,0 @@
;;; lang/assembly/config.el -*- lexical-binding: t; -*-
(def-package! mips-mode :mode "\\.mips$")
(def-package! haxor-mode :mode "\\.hax$")
(def-package! nasm-mode :commands nasm-mode)

View file

@ -1,5 +1,22 @@
#+TITLE: :lang cc
#+TITLE: lang/cc
#+DATE: January 16, 2017
#+SINCE: v2.0
#+STARTUP: inlineimages
* Table of Contents :TOC_3:noexport:
- [[Description][Description]]
- [[Module Flags][Module Flags]]
- [[Plugins][Plugins]]
- [[Prerequisites][Prerequisites]]
- [[irony-server][irony-server]]
- [[MacOS][MacOS]]
- [[Arch Linux][Arch Linux]]
- [[rtags][rtags]]
- [[Configure][Configure]]
- [[Project compile settings][Project compile settings]]
- [[Known issues with bear on macOS][Known issues with bear on macOS]]
* Description
This module adds support for the C-family of languages: C, C++, and Objective-C.
+ Code completion (~company-irony~)
@ -10,34 +27,44 @@ This module adds support for the C-family of languages: C, C++, and Objective-C.
+ Snippets ([[https://github.com/hlissner/emacs-snippets/tree/master/cc-mode][cc-mode]], [[https://github.com/hlissner/emacs-snippets/tree/master/c-mode][c-mode]], [[https://github.com/hlissner/emacs-snippets/tree/master/c++-mode][c++-mode]])
+ Several improvements to C++11 indentation and syntax highlighting.
#+begin_quote
C contends with Haskell and Ruby for my favorite language. That said, it's more
accurate to say I write C, but a C++ feature or three.
** Module Flags
+ ~+irony~ Enable Irony as a backend for code completion, syntax checking, and
eldoc support. This must be disabled to use LSP or another backend.
+ ~+rtags~ Enable rtags integration. A daemon will be spawned the first time you
open a C/C++/ObjC buffer, if one hasn't already.
The module provides nominal support for Objective-C, which I really only use to
inspect generated glue code for iOS mobile apps. Otherwise, I prefer Swift.
#+end_quote
** Plugins
+ [[https://github.com/Kitware/CMake][cmake-mode]]
+ [[https://github.com/chachi/cuda-mode][cuda-mode]]
+ [[https://github.com/liblit/demangle-mode][demangle-mode]]
+ [[https://github.com/jart/disaster][disaster]]
+ [[https://github.com/ludwigpacifici/modern-cpp-font-lock][modern-cpp-font-lock]]
+ [[https://github.com/salmanebah/opencl-mode][opencl-mode]]
+ [[https://github.com/jimhourihan/glsl-mode][glsl-mode]]*
+ [[https://github.com/guidoschmidt/company-glsl][gompany-glsl]]*
+ [[https://github.com/Sarcasm/irony-mode][irony]]*
+ [[https://github.com/ikirill/irony-eldoc][irony-eldoc]]*
+ [[https://github.com/Sarcasm/flycheck-irony][flycheck-irony]]*
+ [[https://github.com/Sarcasm/company-irony][company-irony]]*
+ [[https://github.com/hotpxl/company-irony-c-headers][company-irony-c-headers]]*
+ [[https://github.com/Andersbakken/rtags][rtags]]*
+ [[https://github.com/Andersbakken/rtags][ivy-rtags]] or [[https://github.com/Andersbakken/rtags][helm-rtags]]*
* Table of Contents :TOC:
- [[#install][Install]]
- [[#irony-server][irony-server]]
- [[#rtags][rtags]]
- [[#configure][Configure]]
- [[#compile-settings][Compile settings]]
* Prerequisites
This module requires
* Install
This module requires:
+ irony-server
+ rtags
+ irony-server (if ~+irony~ is enabled)
+ rtags (if ~+rtags~ is enabled)
** irony-server
Irony powers the code completion, eldoc and syntax checking systems.
After installing its dependencies, run ~M-x irony-install-server~ in Emacs.
*** MacOS
Due to linking issues, MacOS users must compile irony-server manually:
#+BEGIN_SRC sh :tangle (if (doom-system-os 'macos) "yes")
#+BEGIN_SRC sh
brew install cmake
brew install llvm # 1gb+ installation! May take a while!
@ -60,18 +87,16 @@ rm -rf irony-mode
#+END_SRC
*** Arch Linux
#+BEGIN_SRC sh :tangle (if (doom-system-os 'arch) "yes")
sudo pacman --needed --noconfirm -S clang cmake
#+BEGIN_SRC sh
pacman -S clang cmake
#+END_SRC
Then run ~M-x irony-install-server~ in Emacs.
** rtags
Code navigation requires an [[https://github.com/Andersbakken/rtags][rtags]] server (~rdm~) installed and running. This
should be available through your OS's package manager.
Code navigation requires an [[https://github.com/Andersbakken/rtags][rtags]] server (~rdm~) installed. This should be
available through your OS's package manager.
This module will auto-start ~rdm~ when you open C/C++ buffers (so long as one
isn't already). If you prefer to run it yourself, outside of Emacs:
isn't already running). If you prefer to run it yourself:
#+BEGIN_SRC sh
rdm &
@ -79,7 +104,7 @@ rc -J $PROJECT_ROOT # loads PROJECT_ROOT's compile_commands.json
#+END_SRC
* Configure
** Compile settings
** Project compile settings
By default, a set of default compile settings are defined in
~+cc-default-compiler-options~ for C, C++ and Objective C. Irony, rtags and
flycheck will fall back to these.
@ -87,7 +112,7 @@ flycheck will fall back to these.
To make these tools aware of project specific build settings, you need a JSON
[[https://sarcasm.github.io/notes/dev/compilation-database.html#ninja][compilation database]] present (i.e. a ~compile_commands.json~ file).
There are [[https://sarcasm.github.io/notes/dev/compilation-database.html][many ways to generate one]]. I use [[http://www.cmake.org/][CMake]] and [[https://github.com/rizsotto/Bear][bear]]:
There are [[https://sarcasm.github.io/notes/dev/compilation-database.html][many ways to generate one]]. I use [[http://www.cmake.org/][CMake]] or [[https://github.com/rizsotto/Bear][bear]]:
#+BEGIN_SRC sh
# For CMake projects
@ -98,7 +123,44 @@ make clean
bear make
#+END_SRC
#+begin_quote
Use ~M-x +cc/reload-compile-db~ to reload your compile db in an already-open
C/C++/ObjC buffer.
*** Known issues with bear on macOS
MacOS' [[https://support.apple.com/en-us/HT204899][System Integrity Protection (SIP)]] might interfere with bear if ~make~ is
under ~/usr/bin/~ which results in an empty compilation database.
From the bear [[https://github.com/rizsotto/Bear#empty-compilation-database-on-os-x-captain-or-fedora][readme]]:
#+begin_quote
Security extension/modes on different operating systems might disable library
preloads. This case Bear behaves normally, but the result compilation database
will be empty. (Please make sure it's not the case when reporting bugs.) Notable
examples for enabled security modes are: OS X 10.11 (check with csrutil status |
grep 'System Integrity Protection'), and Fedora, CentOS, RHEL (check with
sestatus | grep 'SELinux status').
Workaround could be to disable the security feature while running Bear. (This
might involve reboot of your computer, so might be heavy workaround.) Another
option if the build tool is not installed under certain directories. Or use
tools which are using compiler wrappers. (It injects a fake compiler which does
record the compiler invocation and calls the real compiler too.) An example for
such tool might be scan-build. The build system shall respect CC and CXX
environment variables.
#+end_quote
A workaround might be to install ~make~ via Homebrew which puts ~gmake~
under ~/usr/local/~.
#+BEGIN_SRC sh
brew install make
#+END_SRC
#+BEGIN_SRC sh
make clean
bear gmake
#+END_SRC
Additional info:
+ [[https://github.com/rizsotto/Bear/issues/158][Empty compilation database with compiler in /usr/local]]
+ [[https://github.com/rizsotto/Bear/issues/152][Workaround for 'Empty compilation database on OS X Captain]]

View file

@ -1,52 +1,20 @@
;;; lang/cc/autoload.el -*- lexical-binding: t; -*-
;;;###autoload
(defun +cc/reload-compile-db (&optional force-p)
"Reload the current project's JSON compilation database."
(interactive "P")
(unless (memq major-mode '(c-mode c++-mode objc-mode))
(user-error "Not a C/C++/ObjC buffer"))
(unless (doom-project-has! "compile_commands.json")
(user-error "No compile_commands.json file"))
;; first rtag
(when (and (featurep 'rtags)
rtags-enabled
(executable-find "rc"))
(with-temp-buffer
(message "Reloaded compile commands for rtags daemon")
(rtags-call-rc :silent t "-J" (doom-project-root))))
;; then irony
(when (and (featurep 'irony) irony-mode)
(+cc|irony-init-compile-options)))
(add-to-list 'auto-mode-alist '("\\.cl\\'" . opencl-mode))
;;;###autoload
(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
(save-excursion
(goto-char (c-langelem-pos langelem))
;; Detect "[...](" or "[...]{". preceded by "," or "(",
;; and with unclosed brace.
(looking-at-p ".*[(,][ \t]*\\[[^]]*\\][ \t]*[({][^}]*$"))))
0 ; no additional indent
(apply orig-fun args)))
;;;###autoload
(defun +cc/autoclose->-maybe ()
"For some reason smartparens won't autoskip >'s, this hack does."
(interactive)
(if (save-excursion
(backward-char)
(looking-at-p "[^ \t]>"))
(forward-char)
(call-interactively #'self-insert-command)))
;;
;; Library
;;;###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)))
(cond ((eq action 'insert)
(sp-point-after-word-p id action context))
((eq action 'autoskip)
(/= (char-before) 32)))))
;;;###autoload
(defun +cc-sp-point-after-include-p (id action context)
@ -57,33 +25,131 @@
(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"))
'+
'++)))
'+))
(defun +cc-c++-lineup-inclass (langelem)
"Indent inclass lines one level further than access modifier keywords."
(and (eq major-mode 'c++-mode)
(or (assoc 'access-label c-syntactic-context)
(save-excursion
(save-match-data
(re-search-backward
"\\(?:p\\(?:ublic\\|r\\(?:otected\\|ivate\\)\\)\\)"
(c-langelem-pos langelem) t))))
'++))
;;;###autoload
(defun +cc-lineup-arglist-close (langlem)
"Line up the closing brace in an arglist with the opening brace IF cursor is
preceded by the opening brace or a comma (disregarding whitespace in between)."
(when (save-excursion
(save-match-data
(skip-chars-backward " \t\n" (c-langelem-pos langelem))
(memq (char-before) (list ?, ?\( ?\;))))
(c-lineup-arglist langlem)))
(defun +cc--re-search-for (regexp)
(save-excursion
(save-restriction
(save-match-data
(widen)
(goto-char (point-min))
(re-search-forward regexp magic-mode-regexp-match-limit t)))))
;;;###autoload
(defun +cc-c-c++-objc-mode ()
"Uses heuristics to detect `c-mode', `objc-mode' or `c++-mode'.
1. Checks if there are nearby cpp/cc/m/mm files with the same name.
2. Checks for ObjC and C++-specific keywords and libraries.
3. Falls back to `+cc-default-header-file-mode', if set.
4. Otherwise, activates `c-mode'.
This is meant to replace `c-or-c++-mode' (introduced in Emacs 26.1), which
doesn't support specification of the fallback mode and whose heuristics are
simpler."
(let ((base (file-name-sans-extension (buffer-file-name (buffer-base-buffer)))))
(cond ((file-exists-p! (or (concat base ".cpp")
(concat base ".cc")))
(c++-mode))
((or (file-exists-p! (or (concat base ".m")
(concat base ".mm")))
(+cc--re-search-for
(concat "^[ \t\r]*\\(?:"
"@\\(?:class\\|interface\\|property\\|end\\)\\_>"
"\\|#import +<Foundation/Foundation.h>"
"\\|[-+] ([a-zA-Z0-9_]+)"
"\\)")))
(objc-mode))
((+cc--re-search-for
(let ((id "[a-zA-Z0-9_]+") (ws "[ \t\r]+") (ws-maybe "[ \t\r]*"))
(concat "^" ws-maybe "\\(?:"
"using" ws "\\(?:namespace" ws "std;\\|std::\\)"
"\\|" "namespace" "\\(?:" ws id "\\)?" ws-maybe "{"
"\\|" "class" ws id ws-maybe "[:{\n]"
"\\|" "template" ws-maybe "<.*>"
"\\|" "#include" ws-maybe "<\\(?:string\\|iostream\\|map\\)>"
"\\)")))
(c++-mode))
((functionp +cc-default-header-file-mode)
(funcall +cc-default-header-file-mode))
((c-mode)))))
(defun +cc-resolve-include-paths ()
(cl-loop with path = (or buffer-file-name default-directory)
for dir in +cc-default-include-paths
if (file-name-absolute-p dir)
collect dir
else if (projectile-locate-dominating-file path dir)
collect (expand-file-name dir it)))
;;
;; Commands
;;;###autoload
(defun +cc/reload-compile-db ()
"Reload the current project's JSON compilation database."
(interactive)
(unless (memq major-mode '(c-mode c++-mode objc-mode))
(user-error "Not a C/C++/ObjC buffer"))
;; first rtag
(when (and (featurep 'rtags)
rtags-enabled
(executable-find rtags-rc-binary-name))
(with-temp-buffer
(message "Reloaded compile commands for rtags daemon")
(rtags-call-rc :silent t "-J" (or (doom-project-root) default-directory))))
;; then irony
(when (and (featurep 'irony) irony-mode)
(+cc|irony-init-compile-options)))
;;;###autoload
(defun +cc/imenu ()
"Invoke `rtags-imenu' if a running rdm process is available, otherwise invoke
`imenu'."
(interactive)
(call-interactively
(if (and (processp rtags-rdm-process)
(not (eq (process-status rtags-rdm-process) 'exit))
(not (eq (process-status rtags-rdm-process) 'signal)))
#'rtags-imenu
#'imenu)))
;;
;; 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))
(when (memq major-mode '(c-mode c++-mode))
(font-lock-add-keywords
nil '(("\\<[A-Z]*_[0-9A-Z_]+\\>" . font-lock-constant-face)
("\\<[A-Z]\\{3,\\}\\>" . font-lock-constant-face))
t)))
(defvar +cc--project-includes-alist nil)
;;;###autoload
(defun +cc|irony-init-compile-options ()
(defun +cc|init-irony-compile-options ()
"Initialize compiler options for irony-mode. It searches for the nearest
compilation database and initailizes it, otherwise falling back on
`+cc-default-compiler-options' and `+cc-default-include-paths'.
@ -93,9 +159,47 @@ 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-default-compiler-options)))
(cl-loop for path in +cc-default-include-paths
nconc (list "-I" path)))
(doom-project-root)))))
(let ((project-root (doom-project-root))
(include-paths (+cc-resolve-include-paths)))
(setf (alist-get project-root +cc--project-includes-alist)
include-paths)
(irony-cdb--update-compile-options
(append (delq nil (cdr-safe (assq major-mode +cc-default-compiler-options)))
(cl-loop for path in include-paths
collect (format "-I%s" path)))
project-root)))))
;; ;;;###autoload
;; (defun +cc|init-ccls-compile-options ()
;; "TODO"
;; (when (memq major-mode '(c-mode c++-mode objc-mode))
;; (when-let* ((include-paths (+cc-resolve-include-paths)))
;; (let ((args (delq nil (cdr-safe (assq major-mode +cc-default-compiler-options)))))
;; (setf (alist-get (or (lsp-workspace-root)
;; (lsp--suggest-project-root)
;; (doom-project-root))
;; +cc--project-includes-alist)
;; include-paths)
;; (setq ccls-initialization-options
;; `(:clang (:extraArgs
;; [,@(cl-loop for path in include-paths
;; collect (format "-I%s" path))])))))))
;;;###autoload
(defun +cc|init-ffap-integration ()
"Takes the local project include paths and registers them with ffap.
This way, `find-file-at-point' (and `+lookup/file') will know where to find most
header files."
(when-let* ((project-root (or (bound-and-true-p irony--working-directory)
(and (featurep 'lsp)
(or (lsp-workspace-root)
(doom-project-root))))))
(require 'ffap)
(make-local-variable 'ffap-c-path)
(make-local-variable 'ffap-c++-path)
(cl-loop for dir in (or (cdr (assoc project-root +cc--project-includes-alist))
(+cc-resolve-include-paths))
do (add-to-list (pcase major-mode
(`c-mode 'ffap-c-path)
(`c++-mode 'ffap-c++-path))
(expand-file-name dir project-root)))))

View file

@ -1,104 +1,131 @@
;;; lang/cc/config.el --- c, c++, and obj-c -*- lexical-binding: t; -*-
(defvar +cc-default-include-paths (list "include/")
"A list of default paths, relative to a project root, to search for headers in
C/C++. Paths can be absolute. This is ignored if your project has a JSON
compilation database.")
(defvar +cc-default-include-paths
(list "include"
"includes")
"A list of default relative paths which will be searched for up from the
current file, to be passed to irony as extra header search paths. Paths can be
absolute. This is ignored if your project has a compilation database.
This is ignored by ccls.")
(defvar +cc-default-header-file-mode 'c-mode
"Fallback major mode for .h files if all other heuristics fail (in
`+cc-c-c++-objc-mode').")
(defvar +cc-default-compiler-options
`((c-mode . nil)
(c++-mode
. ,(list "-std=c++11" ; use C++11 by default
. ,(list "-std=c++1z" ; use C++17 draft 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++"))))
"-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.")
compilation database is present in the project.
This is ignored by ccls.")
;;
;; Plugins
;;
;; Packages
(def-package! cc-mode
:commands (c-mode c++-mode objc-mode java-mode)
:mode ("\\.mm" . objc-mode)
: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
(concat (file-name-sans-extension buffer-file-name)
".cpp")))
(when-let* ((file (car-safe (projectile-get-other-files
buffer-file-name
(projectile-current-project-files)))))
(equal (file-name-extension file) "cpp")))))
(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)))
(push (cons #'+cc-c++-header-file-p 'c++-mode) magic-mode-alist)
(push (cons #'+cc-objc-header-file-p 'objc-mode) magic-mode-alist)
:mode ("\\.mm\\'" . objc-mode)
:init
(setq-default c-basic-offset tab-width)
(setq-default c-basic-offset tab-width
c-backspace-function #'delete-backward-char
c-default-style "doom")
;; The plusses in c++-mode can be annoying to search for ivy/helm (which reads
;; queries as regexps), so we add these for convenience.
(defalias 'cpp-mode 'c++-mode)
(defvaralias 'cpp-mode-map 'c++-mode-map)
;; Activate `c-mode', `c++-mode' or `objc-mode' depending on heuristics
(add-to-list 'auto-mode-alist '("\\.h\\'" . +cc-c-c++-objc-mode))
;; Ensure find-file-at-point works in C modes, must be added before irony
;; and/or lsp hooks are run.
(add-hook! (c-mode-local-vars c++-mode-local-vars objc-mode-local-vars)
#'+cc|init-ffap-integration)
:config
(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))
(set-electric! '(c-mode c++-mode objc-mode java-mode) :chars '(?\n ?\} ?\{))
(set-docsets! 'c-mode "C")
(set-docsets! 'c++-mode "C++" "Boost")
;;; 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)
(set-rotate-patterns! 'c++-mode
:symbols '(("public" "protected" "private")
("class" "struct")))
(set-pretty-symbols! '(c-mode c++-mode)
;; Functional
;; :def "void "
;; Types
:null "nullptr"
:true "true" :false "false"
:int "int" :float "float"
:str "std::string"
:bool "bool"
;; Flow
:not "!"
:and "&&" :or "||"
:for "for"
:return "return"
:yield "#require")
;;; 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)
;; Custom style, based off of linux
(c-add-style
"doom" '((c-basic-offset . tab-width)
(c-comment-only-line-offset . 0)
(c-hanging-braces-alist (brace-list-open)
(brace-entry-open)
(substatement-open after)
(block-close . c-snug-do-while)
(arglist-cont-nonempty))
(c-cleanup-list brace-else-brace)
(c-offsets-alist
(knr-argdecl-intro . 0)
(substatement-open . 0)
(substatement-label . 0)
(statement-cont . +)
(case-label . +)
;; align args with open brace OR don't indent at all (if open
;; brace is at eolp and close brace is after arg with no trailing
;; comma)
(brace-list-intro . 0)
(brace-list-close . -)
(arglist-intro . +)
(arglist-close +cc-lineup-arglist-close 0)
;; don't over-indent lambda blocks
(inline-open . 0)
(inlambda . 0)
;; indent access keywords +1 level, and properties beneath them
;; another level
(access-label . -)
(inclass +cc-c++-lineup-inclass +)
(label . 0))))
;;; 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)
(define-key! c++-mode-map "<" nil ">" nil)
;; ...and leave it to smartparens
(sp-with-modes '(c++-mode objc-mode)
(sp-local-pair "<" ">"
:when '(+cc-sp-point-is-template-p +cc-sp-point-after-include-p)
:post-handlers '(("| " "SPC"))))
(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")))))
@ -107,135 +134,117 @@ compilation database is present in the project.")
(def-package! irony
:after cc-mode
:commands irony-install-server
:preface (setq irony-server-install-prefix (concat doom-etc-dir "irony-server/"))
:unless (featurep! +lsp)
:commands (irony-install-server irony-mode)
:preface
(setq irony-server-install-prefix (concat doom-etc-dir "irony-server/"))
:init
(defun +cc|init-irony-mode ()
(when (memq major-mode '(c-mode c++-mode objc-mode))
(irony-mode +1)))
(add-hook! (c-mode c++-mode objc-mode) #'+cc|init-irony-mode)
(if (file-directory-p irony-server-install-prefix)
(irony-mode +1)
(message "Irony server isn't installed")))
(add-hook! (c-mode-local-vars c++-mode-local-vars objc-mode-local-vars)
#'+cc|init-irony-mode)
:config
(unless (file-directory-p irony-server-install-prefix)
(warn "irony-mode: server isn't installed; run M-x irony-install-server"))
(setq irony-cdb-search-directory-list '("." "build" "build-conda"))
;; Initialize compilation database, if present. Otherwise, fall back on
;; `+cc-default-compiler-options'.
(add-hook 'irony-mode-hook #'+cc|irony-init-compile-options))
(add-hook 'irony-mode-hook #'+cc|init-irony-compile-options)
(def-package! irony-eldoc
:after irony
:hook (irony-mode . irony-eldoc))
(def-package! irony-eldoc
:hook (irony-mode . irony-eldoc))
(def-package! flycheck-irony
:when (featurep! :feature syntax-checker)
:after irony
:config
(add-hook 'irony-mode-hook #'flycheck-mode)
(flycheck-irony-setup))
(def-package! flycheck-irony
:when (featurep! :tools flycheck)
:config (flycheck-irony-setup))
;;
;; Tools
;;
(def-package! disaster :commands disaster)
(def-package! company-irony
:when (featurep! :completion company)
:init
(set-company-backend! 'irony-mode
'(:separate company-irony-c-headers company-irony))
:config
(require 'company-irony-c-headers)))
;;
;; Major modes
;;
(def-package! cmake-mode
:mode "/CMakeLists\\.txt$"
:mode "\\.cmake\\$"
:config
(set! :company-backend 'cmake-mode '(company-cmake company-yasnippet)))
(def-package! company-cmake ; for `cmake-mode'
:when (featurep! :completion company)
:after cmake-mode
:config (set-company-backend! 'cmake-mode 'company-cmake))
(def-package! cuda-mode :mode "\\.cuh?$")
(def-package! opencl-mode :mode "\\.cl$")
(def-package! demangle-mode
:hook llvm-mode)
(def-package! glsl-mode
:mode "\\.glsl$"
:mode "\\.vert$"
:mode "\\.frag$"
:mode "\\.geom$")
;;
;; Company plugins
;;
(def-package! company-cmake
:when (featurep! :completion company)
:after cmake-mode)
(def-package! company-irony
:when (featurep! :completion company)
:after irony)
(def-package! company-irony-c-headers
:when (featurep! :completion company)
:after company-irony)
(def-package! company-glsl
(def-package! company-glsl ; for `glsl-mode'
:when (featurep! :completion company)
:after glsl-mode
:config
(if (executable-find "glslangValidator")
(warn "glsl-mode: couldn't find glslangValidator, disabling company-glsl")
(set! :company-backend 'glsl-mode '(company-glsl))))
:config (set-company-backend! 'glsl-mode 'company-glsl))
;;
;; Rtags Support
;;
(def-package! rtags
:after cc-mode
:unless (featurep! +lsp)
:commands rtags-executable-find
:preface
(setq rtags-install-path (concat doom-etc-dir "rtags/"))
:init
(defun +cc|init-rtags ()
"Start an rtags server in c-mode and c++-mode buffers."
(when (and (require 'rtags nil t)
(rtags-executable-find rtags-rdm-binary-name))
(rtags-start-process-unless-running)))
(add-hook! (c-mode-local-vars c++-mode-local-vars objc-mode-local-vars)
#'+cc|init-rtags)
:config
(setq rtags-autostart-diagnostics t
rtags-use-bookmarks nil
rtags-completions-enabled nil
rtags-display-result-backend
(cond ((featurep! :completion ivy) 'ivy)
((featurep! :completion helm) 'helm)
('default))
;; If not using ivy or helm to view results, use a pop-up window rather
;; than displaying it in the current window...
rtags-results-buffer-other-window t
;; ...and don't auto-jump to first match before making a selection.
rtags-jump-to-first-match nil)
(let ((bins (cl-remove-if-not #'executable-find '("rdm" "rc"))))
(if (/= (length bins) 2)
(warn "cc-mode: couldn't find %s, disabling rtags support" bins)
(add-hook! (c-mode c++-mode) #'rtags-start-process-unless-running)
(set! :jump '(c-mode c++-mode)
:definition #'rtags-find-symbol-at-point
:references #'rtags-find-references-at-point)))
(set-lookup-handlers! '(c-mode c++-mode)
:definition #'rtags-find-symbol-at-point
:references #'rtags-find-references-at-point)
(add-hook 'doom-cleanup-hook #'rtags-cancel-process)
(add-hook! kill-emacs (ignore-errors (rtags-cancel-process)))
(add-hook! 'kill-emacs-hook (ignore-errors (rtags-cancel-process)))
;; Use rtags-imenu instead of imenu/counsel-imenu
(map! :map (c-mode-map c++-mode-map) [remap imenu] #'rtags-imenu)
(define-key! (c-mode-map c++-mode-map) [remap imenu] #'+cc/imenu)
(add-hook 'rtags-jump-hook #'evil-set-jump)
(when (featurep 'evil)
(add-hook 'rtags-jump-hook #'evil-set-jump))
(add-hook 'rtags-after-find-file-hook #'recenter))
(def-package! ivy-rtags
:when (featurep! :completion ivy)
:after rtags
:init
;; NOTE Ivy integration breaks when rtags is byte-compiled with Emacs 26 or
;; later, so we un-byte-compile it before we load it.
(eval-when-compile
(when (>= emacs-major-version 26)
(when-let* ((elc-file (locate-library "rtags.elc" t doom--package-load-path)))
(delete-file elc-file))))
:config (setq rtags-display-result-backend 'ivy))
(def-package! helm-rtags
:when (featurep! :completion helm)
:after rtags
:config (setq rtags-display-result-backend 'helm))
;;
;; LSP
(def-package! ccls
:when (featurep! +lsp)
:hook ((c-mode-local-vars c++-mode-local-vars objc-mode-local-vars) . +cc|init-ccls)
:init
(after! projectile
(add-to-list 'projectile-globally-ignored-directories ".ccls-cache")
(add-to-list 'projectile-project-root-files-bottom-up ".ccls-root")
(add-to-list 'projectile-project-root-files-top-down-recurring "compile_commands.json"))
:config
(defun +cc|init-ccls ()
(setq-local company-transformers nil)
(setq-local company-lsp-async t)
(setq-local company-lsp-cache-candidates nil)
(lsp)))

18
modules/lang/cc/doctor.el Normal file
View file

@ -0,0 +1,18 @@
;; -*- lexical-binding: t; no-byte-compile: t; -*-
;;; lang/cc/doctor.el
(when (require 'rtags nil t)
;; rtags
(let ((bins (cl-remove-if #'executable-find `(,rtags-rdm-binary-name ,rtags-rc-binary-name))))
(when (/= (length bins) 0)
(warn! "Couldn't find the rtag client and/or server programs %s. Disabling rtags support" bins))))
;; irony server
(when (require 'irony nil t)
(unless (file-directory-p irony-server-install-prefix)
(warn! "Irony server isn't installed. Run M-x irony-install-server")))
(when (featurep! :completion company)
;; glslangValidator
(unless (executable-find "glslangValidator")
(warn! "Couldn't find glslangValidator. GLSL code completion is disabled")))

View file

@ -5,22 +5,24 @@
(package! cuda-mode)
(package! demangle-mode)
(package! disaster)
(package! glsl-mode)
(package! irony)
(package! irony-eldoc)
(package! modern-cpp-font-lock)
(package! opencl-mode)
(when (featurep! :feature syntax-checker)
(package! flycheck-irony))
(when (package! glsl-mode)
(when (featurep! :completion company)
(package! company-glsl :recipe (:fetcher github :repo "Kaali/company-glsl"))))
(when (featurep! :completion company)
(package! company-glsl :recipe (:fetcher github :repo "Kaali/company-glsl"))
(package! company-irony)
(package! company-irony-c-headers))
(package! rtags)
(when (featurep! :completion ivy)
(package! ivy-rtags))
(when (featurep! :completion helm)
(package! helm-rtags))
(if (featurep! +lsp)
(package! ccls)
(when (package! irony)
(package! irony-eldoc)
(when (featurep! :tools flycheck)
(package! flycheck-irony))
(when (featurep! :completion company)
(package! company-irony)
(package! company-irony-c-headers)))
(when (package! rtags)
(when (featurep! :completion ivy)
(package! ivy-rtags))
(when (featurep! :completion helm)
(package! helm-rtags))))

View file

@ -0,0 +1,14 @@
;;; lang/clojure/autoload.el -*- lexical-binding: t; -*-
;;;###autoload
(defun +clojure/repl (&optional arg)
"Open a Cider REPL and return the buffer."
(interactive "P")
(cider-jack-in arg)
(current-buffer))
;;;###autoload
(defun +clojure/cider-switch-to-repl-buffer-and-switch-ns ()
"TODO"
(interactive)
(cider-switch-to-repl-buffer t))

View file

@ -1,44 +1,118 @@
;;; lang/clojure/config.el -*- lexical-binding: t; -*-
(def-package! clojure-mode
:mode "\\.clj$"
:mode ("\\.cljs$" . clojurescript-mode)
:config
(map! :map clojure-mode-map
(:localleader
:n "'" #'cider-jack-in
:n "\"" #'cider-jack-in-clojurescript
:n "B" #'cider-switch-to-repl-buffer
:n "b" #'cider-eval-buffer
:n "n" #'cider-repl-set-ns
:n "j" #'cider-find-var
:n "d" #'cider-doc
:n "c" #'cider-repl-clear-buffer
:n "p" #'cider-eval-sexp-at-point
:n "r" #'cider-eval-region)))
(def-package! clj-refactor
:after clojure-mode
:config
;; setup some extra namespace auto completion for great awesome
(dolist (mapping '(("re-frame" . "re-frame.core")
("reagent" . "reagent.core")
("str" . "clojure.str")))
(add-to-list 'cljr-magic-require-namespaces mapping t)))
;; `clojure-mode'
(add-hook 'clojure-mode-hook #'rainbow-delimiters-mode)
(def-package! cider
;; NOTE: if you don't have an org directory set (the dir doesn't exist), cider jack in won't work.
:commands (cider-jack-in cider-mode cider-jack-in-clojurescript)
;; NOTE: if you don't have an org directory set (the dir doesn't exist),
;; cider jack in won't work.
:commands (cider-jack-in cider-jack-in-clojurescript)
:hook (clojure-mode-local-vars . cider-mode)
:init
(set-repl-handler! 'clojure-mode #'+clojure/repl)
(set-eval-handler! 'clojure-mode #'cider-eval-region)
(set-lookup-handlers! 'clojure-mode
:definition #'cider-find-dwim
:documentation #'cider-doc)
(add-hook 'cider-mode-hook #'eldoc-mode)
:config
(setq nrepl-hide-special-buffers t)
(set-popup-rules!
'(("^\\*cider-error*" :ignore t)
("^\\*cider-repl" :quit nil)
("^\\*cider-repl-history" :vslot 2 :ttl nil)))
;; settings for cider repl as a popup (prevent it from being closed on escape, especially.)
(set! :popup "^\\*cider" :regexp t :noselect t :noesc t)
(setq nrepl-hide-special-buffers t
nrepl-log-messages nil
cider-font-lock-dynamically '(macro core function var)
cider-overlays-use-font-lock t
cider-prompt-for-symbol nil
cider-repl-display-help-banner nil
cider-repl-history-display-duplicates nil
cider-repl-history-display-style 'one-line
cider-repl-history-file (concat doom-cache-dir "cider-repl-history")
cider-repl-history-highlight-current-entry t
cider-repl-history-quit-action 'delete-and-restore
cider-repl-history-highlight-inserted-item t
cider-repl-history-size 1000
cider-repl-pop-to-buffer-on-connect 'display-only
cider-repl-result-prefix ";; => "
cider-repl-print-length 100
cider-repl-use-clojure-font-lock t
cider-repl-use-pretty-printing t
cider-repl-wrap-history nil
cider-stacktrace-default-filters '(tooling dup))
;; Setup cider for clojurescript / figwheel dev.
(setq cider-cljs-lein-repl
"(do (require 'figwheel-sidecar.repl-api)
(figwheel-sidecar.repl-api/start-figwheel!)
(figwheel-sidecar.repl-api/cljs-repl))"))
(map! (:localleader
(:map clojure-mode-map
"'" #'cider-jack-in
"\"" #'cider-jack-in-clojurescript
(:prefix ("e" . "eval")
"d" #'cider-eval-defun-at-point
"D" #'cider-insert-defun-in-repl
"e" #'cider-eval-last-sexp
"E" #'cider-insert-last-sexp-in-repl
"r" #'cider-eval-region
"R" #'cider-insert-region-in-repl
"u" #'cider-undef)
(:prefix ("g" . "go/jump")
"b" #'cider-pop-back
"g" #'cider-find-var
"n" #'cider-find-ns)
(:prefix ("h" . "help")
"n" #'cider-find-ns
"a" #'cider-apropos
"d" #'cider-doc
"g" #'cider-grimoire-web
"j" #'cider-javadoc)
(:prefix ("i" . "inspect")
"i" #'cider-inspect
"r" #'cider-inspect-last-result)
(:prefix ("m" . "macro")
"e" #'cider-macroexpand-1
"E" #'cider-macroexpand-al)
(:prefix ("n" . "namespace")
"n" #'cider-browse-ns
"N" #'cider-browse-ns-all)
(:prefix ("r" . "repl")
"n" #'cider-repl-set-ns
"q" #'cider-quit
"r" #'cider-refresh
"R" #'cider-restart
"b" #'cider-switch-to-repl-buffer
"B" #'+clojure/cider-switch-to-repl-buffer-and-switch-ns
"c" #'cider-find-and-clear-repl-output)))
(:when (featurep! :feature evil +everywhere)
:map cider-repl-mode-map
:i [S-return] #'cider-repl-newline-and-indent
(:localleader
("n" #'cider-repl-set-ns
"q" #'cider-quit
"r" #'cider-ns-refresh
"R" #'cider-restart
"c" #'cider-repl-clear-buffer))
:map cider-repl-history-mode-map
:i [return] #'cider-repl-history-insert-and-quit
:i "q" #'cider-repl-history-quit
:i "l" #'cider-repl-history-occur
:i "s" #'cider-repl-history-search-forward
:i "r" #'cider-repl-history-search-backward
:i "U" #'cider-repl-history-undo-other-window)))
(def-package! clj-refactor
:hook (clojure-mode . clj-refactor-mode)
:init
(set-lookup-handlers! 'clojure-mode
:references #'cljr-find-usages)
:config
(map! :map clojure-mode-map
:localleader
:desc "refactor" "R" #'hydra-cljr-help-menu/body))
(def-package! flycheck-joker
:when (featurep! :tools flycheck)
:after flycheck)

View file

@ -4,3 +4,5 @@
(package! cider)
(package! clj-refactor)
(when (featurep! :tools flycheck)
(package! flycheck-joker))

View file

@ -0,0 +1,11 @@
;;; lang/common-lisp/autoload/common-lisp.el -*- lexical-binding: t; -*-
;;;###autoload
(defun +common-lisp*sly-last-sexp (command &rest args)
"In normal-state or motion-state, last sexp ends at point."
(if (and (not evil-move-beyond-eol)
(or (evil-normal-state-p) (evil-motion-state-p)))
(save-excursion
(unless (or (eobp) (eolp)) (forward-char))
(apply command args))
(apply command args)))

View file

@ -0,0 +1,245 @@
;;; lang/common-lisp/config.el -*- lexical-binding: t; -*-
;; `lisp-mode' is loaded at startup. In order to lazy load its config we need to
;; pretend it isn't loaded
(defer-feature! lisp-mode)
;;
;; packages
(defvar inferior-lisp-program "sbcl")
(after! lisp-mode
(set-repl-handler! 'lisp-mode #'sly-mrepl)
(set-eval-handler! 'lisp-mode #'sly-eval-region)
(set-lookup-handlers! 'lisp-mode
:definition #'sly-edit-definition
:documentation #'sly-describe-symbol)
(add-hook 'lisp-mode-hook #'rainbow-delimiters-mode))
(after! sly
(setq sly-mrepl-history-file-name (concat doom-cache-dir "sly-mrepl-history")
sly-kill-without-query-p t
sly-net-coding-system 'utf-8-unix
;; Change this to `sly-flex-completions' for fuzzy completion
sly-complete-symbol-function 'sly-simple-completions)
(set-popup-rules!
'(("^\\*sly-mrepl" :vslot 2 :quit nil :ttl nil)
("^\\*sly-compilation" :vslot 3 :ttl nil)
("^\\*sly-traces" :vslot 4 :ttl nil)
;; Do not display debugger or inspector buffers in a popup window. These
;; buffers are meant to be displayed with sufficient vertical space.
("^\\*sly-\\(?:db\\|inspector\\)" :ignore t)))
(sp-with-modes '(sly-mrepl-mode)
(sp-local-pair "'" "'" :actions nil)
(sp-local-pair "`" "`" :actions nil))
(defun +common-lisp|cleanup-sly-maybe ()
"Kill processes and leftover buffers when killing the last sly buffer."
(unless (cl-loop for buf in (delq (current-buffer) (buffer-list))
if (and (buffer-local-value 'sly-mode buf)
(get-buffer-window buf))
return t)
(dolist (conn (sly--purge-connections))
(sly-quit-lisp-internal conn 'sly-quit-sentinel t))
(let (kill-buffer-hook kill-buffer-query-functions)
(mapc #'kill-buffer
(cl-loop for buf in (delq (current-buffer) (buffer-list))
if (buffer-local-value 'sly-mode buf)
collect buf)))))
(defun +common-lisp|init-sly ()
"Attempt to auto-start sly when opening a lisp buffer."
(cond ((or (doom-temp-buffer-p (current-buffer))
(sly-connected-p)))
((executable-find inferior-lisp-program)
(let ((sly-auto-start 'always))
(sly-auto-start)
(add-hook 'kill-buffer-hook #'+common-lisp|cleanup-sly-maybe nil t)))
((message "WARNING: Couldn't find `inferior-lisp-program' (%s)"
inferior-lisp-program))))
(add-hook 'sly-mode-hook #'+common-lisp|init-sly)
(defun +common-lisp*refresh-sly-version (version conn)
"Update `sly-protocol-version', which will likely be incorrect or nil due to
an issue where `load-file-name' is incorrect. Because Doom's packages are
installed through an external script (bin/doom), `load-file-name' is set to
bin/doom while packages at compile-time (not a runtime though)."
(unless sly-protocol-version
(setq sly-protocol-version (sly-version nil (locate-library "sly.el"))))
(advice-remove #'sly-check-version #'+common-lisp*refresh-sly-version))
(advice-add #'sly-check-version :before #'+common-lisp*refresh-sly-version)
(map! :localleader
:map lisp-mode-map
:desc "Sly" "'" #'sly
:desc "Sly (ask)" ";" (λ! () (let ((current-prefix-arg '-)) (sly nil nil t)))
(:prefix ("g" . "Go")
:desc "Go back" "b" #'sly-pop-find-definition-stack
:desc "Go to" "d" #'sly-edit-definition
:desc "Go to (other window)" "D" #'sly-edit-definition-other-window
:desc "Next note" "n" #'sly-next-note
:desc "Previous note" "N" #'sly-previous-note
:desc "Next sticker" "s" #'sly-stickers-next-sticker
:desc "Previous sticker" "S" #'sly-stickers-prev-sticker)
(:prefix ("h" . "Help")
:desc "Who calls" "<" #'sly-who-calls
:desc "Calls who" ">" #'sly-calls-who
:desc "Lookup format directive" "~" #'hyperspec-lookup-format
:desc "Lookup reader macro" "#" #'hyperspec-lookup-reader-macro
:desc "Apropos" "a" #'sly-apropos
:desc "Who binds" "b" #'sly-who-binds
:desc "Disassemble symbol" "d" #'sly-disassemble-symbol
:desc "Describe symbol" "h" #'sly-describe-symbol
:desc "HyperSpec lookup" "H" #'sly-hyperspec-lookup
:desc "Who macro-expands" "m" #'sly-who-macroexpands
:desc "Apropos package" "p" #'sly-apropos-package
:desc "Who references" "r" #'sly-who-references
:desc "Who specializes" "s" #'sly-who-specializes
:desc "Who sets" "S" #'sly-who-sets)
(:prefix ("c" . "Compile")
:desc "Compile file" "c" #'sly-compile-file
:desc "Compile/load file" "C" #'sly-compile-and-load-file
:desc "Compile toplevel form" "f" #'sly-compile-defun
:desc "Load file" "l" #'sly-load-file
:desc "Remove notes" "n" #'sly-remove-notes
:desc "Compile region" "r" #'sly-compile-region)
(:prefix ("e" . "Evaluate")
:desc "Evaulate buffer" "b" #'sly-eval-buffer
:desc "Evaluate last" "e" #'sly-eval-last-expression
:desc "Evaluate/print last" "E" #'sly-eval-print-last-expression
:desc "Evaluate defun" "f" #'sly-eval-defun
:desc "Undefine function" "F" #'sly-undefine-function
:desc "Evaluate region" "r" #'sly-eval-region)
(:prefix ("m" . "Macro")
:desc "Macrostep" "e" #'macrostep-expand)
(:prefix ("r" . "REPL")
:desc "Clear REPL" "c" #'sly-mrepl-clear-repl
:desc "Quit connection" "q" #'sly-quit-lisp
:desc "Restart connection" "r" #'sly-restart-inferior-lisp
:desc "Sync REPL" "s" #'sly-mrepl-sync)
(:prefix ("s" . "Stickers")
:desc "Toggle breaking stickers" "b" #'sly-stickers-toggle-break-on-stickers
:desc "Clear defun stickers" "c" #'sly-stickers-clear-defun-stickers
:desc "Clear buffer stickers" "C" #'sly-stickers-clear-buffer-stickers
:desc "Fetch stickers" "f" #'sly-stickers-fetch
:desc "Replay stickers" "r" #'sly-stickers-replay
:desc "Add/remove sticker" "s" #'sly-stickers-dwim)
(:prefix ("t" . "Trace")
:desc "Toggle" "t" #'sly-toggle-trace-fdefinition
:desc "Toggle (fancy)" "T" #'sly-toggle-fancy-trace
:desc "Untrace all" "u" #'sly-untrace-all))
(when (featurep! :feature evil +everywhere)
(add-hook 'sly-mode-hook #'evil-normalize-keymaps)
(add-hook 'sly-popup-buffer-mode-hook #'evil-normalize-keymaps)
(unless evil-move-beyond-eol
(advice-add #'sly-eval-last-expression :around #'+common-lisp*sly-last-sexp)
(advice-add #'sly-pprint-eval-last-expression :around #'+common-lisp*sly-last-sexp)
(advice-add #'sly-eval-print-last-expression :around #'+common-lisp*sly-last-sexp)
(advice-add #'sly-eval-last-expression-in-repl :around #'+common-lisp*sly-last-sexp))
(set-evil-initial-state!
'(sly-db-mode sly-inspector-mode sly-popup-buffer-mode sly-xref-mode)
'normal)
(evil-define-key 'insert sly-mrepl-mode-map
[S-return] #'newline-and-indent
[backspace] #'sp-backward-delete-char
[up] (λ! () (evil-goto-line) (comint-previous-input 1))
[down] (λ! () (evil-goto-line) (comint-next-input 1)))
(evil-define-key 'normal sly-parent-map
(kbd "C-t") #'sly-pop-find-definition-stack)
(evil-define-key 'normal sly-popup-buffer-mode-map
(kbd "C-t") 'sly-pop-find-definition-stack
"q" 'quit-window)
(evil-define-key 'normal sly-db-mode-map
[follow-link] 'mouse-face
[mouse-2] 'sly-db-default-action/mouse
[remap quit-window] 'sly-db-quit
(kbd "C-i") 'sly-db-cycle
(kbd "C-j") 'sly-db-down
(kbd "C-k") 'sly-db-up
(kbd "C-m") 'sly-db-default-action
(kbd "C-S-j") 'sly-db-details-down
(kbd "C-S-k") 'sly-db-details-up
"]" 'sly-db-details-down
"[" 'sly-db-details-up
"0" 'sly-db-invoke-restart-0
"1" 'sly-db-invoke-restart-1
"2" 'sly-db-invoke-restart-2
"3" 'sly-db-invoke-restart-3
"4" 'sly-db-invoke-restart-4
"5" 'sly-db-invoke-restart-5
"6" 'sly-db-invoke-restart-6
"7" 'sly-db-invoke-restart-7
"8" 'sly-db-invoke-restart-8
"9" 'sly-db-invoke-restart-9
"a" 'sly-db-abort
"A" 'sly-db-break-with-system-debugger
"b" 'sly-db-break-on-return
"B" 'sly-db-break-with-default-debugger
"c" 'sly-db-continue
"C" 'sly-db-inspect-condition
"d" 'sly-db-pprint-eval-in-frame
"D" 'sly-db-disassemble
"e" 'sly-db-eval-in-frame
"g:" 'sly-interactive-eval
"g?" 'describe-mode
"gg" 'sly-db-beginning-of-backtrace
"gj" 'sly-db-down
"gk" 'sly-db-up
"gr" 'sly-db-restart-frame
"G" 'sly-db-end-of-backtrace
"i" 'sly-db-inspect-in-frame
"I" 'sly-db-invoke-restart-by-name
"n" 'sly-db-next
"o" 'sly-db-out
"P" 'sly-db-print-condition
"q" 'sly-db-quit
"R" 'sly-db-return-from-frame
"s" 'sly-db-step
"S" 'sly-db-show-frame-source
"t" 'sly-db-toggle-details)
(evil-define-key 'normal sly-inspector-mode-map
[backtab] 'backward-button
[return] 'push-button
[(shift tab)] 'backward-button
(kbd "<M-return>") 'sly-mrepl-copy-part-to-repl
(kbd "C-i") 'next-button
(kbd "C-m") 'push-button
"e" 'sly-inspector-eval
"gb" 'sly-inspector-pop
"gj" 'sly-inspector-next
"gr" 'sly-inspector-reinspect
"gR" 'sly-inspector-fetch-all
"gv" 'sly-inspector-toggle-verbose
"h" 'sly-inspector-history
"k" 'backward-button
"K" 'sly-inspector-describe-inspectee
"p" 'sly-button-pretty-print
"q" 'sly-inspector-quit)
(evil-define-key 'normal sly-mode-map
(kbd "C-t") 'sly-pop-find-definition-stack)
(evil-define-key 'normal sly-xref-mode-map
[return] 'sly-goto-xref
(kbd "S-<return>") 'sly-show-xref
(kbd "C-j") 'sly-xref-next-line
(kbd "C-k") 'sly-xref-prev-line
"]" 'sly-xref-next-line
"[" 'sly-xref-prev-line
"gj" 'sly-xref-next-line
"gk" 'sly-xref-prev-line
"go" 'sly-show-xref
"gr" 'sly-recompile-xref
"gR" 'sly-recompile-all-xrefs
"q" 'quit-window
"r" 'sly-xref-retract)))
(def-package! sly-repl-ansi-color
:defer t
:init
(add-to-list 'sly-contribs 'sly-repl-ansi-color nil #'eq))

View file

@ -0,0 +1,6 @@
;;; lang/common-lisp/doctor.el -*- lexical-binding: t; -*-
(when (require 'sly nil t)
(unless (executable-find inferior-lisp-program)
(warn! "Couldn't find your `inferior-lisp-program' (%s). Is it installed?"
inferior-lisp-program)))

View file

@ -0,0 +1,6 @@
;; -*- no-byte-compile: t; -*-
;;; lang/common-lisp/packages.el
(package! sly)
(package! sly-macrostep)
(package! sly-repl-ansi-color)

View file

@ -0,0 +1,6 @@
#+TITLE: :lang coq
This module adds [[https://coq.inria.fr][coq]] support, powered by [[https://proofgeneral.github.io][Proof General]].
+ Code completion ([[https://github.com/cpitclaudel/company-coq][company-coq]])
+ [[https://github.com/hlissner/emacs-snippets/tree/master/coq-mode][Snippets]]

View file

@ -0,0 +1,4 @@
;;; lang/coq/autoload.el -*- lexical-binding: t; -*-
;;;###autoload
(add-hook 'coq-mode-hook #'company-coq-mode)

View file

@ -0,0 +1,18 @@
;;; lang/coq/config.el -*- lexical-binding: t; -*-
;; `coq'
(setq proof-electric-terminator-enable t)
;; We've replaced coq-mode abbrevs with yasnippet snippets (in the snippets
;; library included with Doom).
(setq coq-mode-abbrev-table '())
(after! company-coq
(set-popup-rule! "^\\*\\(?:response\\|goals\\)\\*" :ignore t)
(set-lookup-handlers! 'company-coq-mode
:definition #'company-coq-jump-to-definition
:references #'company-coq-grep-symbol
:documentation #'company-coq-doc)
(unless (featurep! :completion company)
(setq company-coq-disabled-features '(company company-defaults))))

View file

@ -0,0 +1,6 @@
;; -*- no-byte-compile: t; -*-
;;; lang/coq/packages.el
(package! proof-general)
(package! company-coq)

View file

@ -1,15 +1,21 @@
;;; lang/crystal/config.el -*- lexical-binding: t; -*-
(def-package! crystal-mode
:mode "\\.cr$"
:interpreter "crystal"
:config
(set! :eval 'crystal-mode
'((:command . "crystal")
(:exec . "%c %s")
(:description . "Run Crystal script"))))
(after! crystal-mode
(set-lookup-handlers! 'crystal-mode
:definition #'crystal-def-jump
:references #'crystal-tool-imp)
(set-eval-handler! 'crystal-mode
'((:command . "crystal")
(:exec . "%c %s")
(:description . "Run Crystal script")))
(after! dtrt-indent
(add-to-list 'dtrt-indent-hook-mapping-list '(crystal-mode ruby crystal-indent-level))))
(def-package! flycheck-crystal
:after crystal-mode
:config (add-hook 'crystal-mode-hook #'flycheck-mode))
:when (featurep! :tools flycheck)
:after crystal-mode)
(def-package! inf-crystal
:commands crystal-switch-to-inf)

View file

@ -0,0 +1,5 @@
;; -*- lexical-binding: t; no-byte-compile: t; -*-
;;; lang/crystal/doctor.el
(unless (executable-find "icr")
(warn! "Couldn't find icr. REPL will not work"))

View file

@ -3,4 +3,4 @@
(package! crystal-mode)
(package! flycheck-crystal)
(package! inf-crystal)

View file

@ -0,0 +1,28 @@
#+TITLE: :lang csharp
This module adds C# support to Emacs.
#+begin_quote
I don't use C# for much else than Unity3D and, seldomly, for Mono game
development on Linux.
#+end_quote
* Table of Contents :TOC:
- [[Install][Install]]
- [[MacOS][MacOS]]
- [[Arch Linux][Arch Linux]]
* Install
This module needs:
+ omnisharp-roslyn (install with ~M-x omnisharp-install-server~)
+ .NET SDKs (on Windows)
+ Mono (on UNIX platforms)
** MacOS
=TODO=
** Arch Linux
#+BEGIN_SRC sh :dir /sudo:: :tangle (if (doom-system-os 'arch) "yes")
sudo pacman --needed --noconfirm -S mono
#+END_SRC

View file

@ -0,0 +1,10 @@
;;; lang/csharp/autoload.el -*- lexical-binding: t; -*-
;;;###autoload
(defun +csharp-sp-point-in-type-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)
(cond ((eq action 'insert)
(sp-point-after-word-p id action context))
((eq action 'autoskip)
(/= (char-before) 32)))))

View file

@ -1,49 +1,66 @@
;;; lang/csharp/config.el -*- lexical-binding: t; -*-
(def-package! csharp-mode :mode "\\.cs$")
(after! csharp-mode
(add-hook 'csharp-mode-hook #'rainbow-delimiters-mode)
(set-electric! 'csharp-mode :chars '(?\n ?\}))
(set-rotate-patterns! 'csharp-mode
:symbols '(("public" "protected" "private")
("class" "struct")))
(sp-local-pair 'csharp-mode "<" ">"
:when '(+csharp-sp-point-in-type-p)
:post-handlers '(("| " "SPC"))))
(def-package! omnisharp
:after csharp-mode
:hook (csharp-mode . omnisharp-mode)
:commands omnisharp-install-server
:preface
(setq omnisharp-auto-complete-want-documentation nil
omnisharp-server-executable-path (concat doom-local-dir "OmniSharp.exe"))
omnisharp-cache-directory (concat doom-cache-dir "omnisharp"))
:config
(if (file-exists-p omnisharp-server-executable-path)
(add-hook! csharp-mode #'(eldoc-mode flycheck-mode omnisharp-mode))
(warn "csharp-mode: omnisharp server isn't installed, completion won't work"))
(defun +csharp|cleanup-omnisharp-server ()
"Clean up the omnisharp server once you kill the last csharp-mode buffer."
(unless (doom-buffers-in-mode 'csharp-mode (buffer-list))
(omnisharp-stop-server)))
(add-hook! csharp-mode
(add-hook 'kill-buffer-hook #'+csharp|cleanup-omnisharp-server nil t))
(set! :company-backend 'csharp-mode '(company-omnisharp))
(set-company-backend! 'csharp-mode 'company-omnisharp)
(set-lookup-handlers! 'csharp-mode
:definition #'omnisharp-go-to-definition
:references #'omnisharp-find-usages
:documentation #'omnisharp-current-type-documentation)
(map! :map omnisharp-mode-map
:m "gd" #'omnisharp-go-to-definition
(:localleader
:n "b" #'omnisharp-recompile
(:prefix "r"
:n "i" #'omnisharp-fix-code-issue-at-point
:n "u" #'omnisharp-fix-usings
:n "r" #'omnisharp-rename
:n "a" #'omnisharp-show-last-auto-complete-result
:n "o" #'omnisharp-show-overloads-at-point)
(:prefix "f"
:n "u" #'omnisharp-find-usages
:n "i" #'omnisharp-find-implementations
:n "f" #'omnisharp-navigate-to-current-file-member
:n "m" #'omnisharp-navigate-to-solution-member
:n "M" #'omnisharp-navigate-to-solution-file-then-file-member
:n "F" #'omnisharp-navigate-to-solution-file
:n "r" #'omnisharp-navigate-to-region
:n "ti" #'omnisharp-current-type-information
:n "td" #'omnisharp-current-type-documentation)
(:prefix "t"
:n "r" (λ! (omnisharp-unit-test "fixture"))
:n "s" (λ! (omnisharp-unit-test "single"))
:n "a" (λ! (omnisharp-unit-test "all"))))))
(map! :localleader
:map omnisharp-mode-map
"b" #'omnisharp-recompile
(:prefix "r"
"i" #'omnisharp-fix-code-issue-at-point
"u" #'omnisharp-fix-usings
"r" #'omnisharp-rename
"a" #'omnisharp-show-last-auto-complete-result
"o" #'omnisharp-show-overloads-at-point)
(:prefix "f"
"u" #'omnisharp-find-usages
"i" #'omnisharp-find-implementations
"f" #'omnisharp-navigate-to-current-file-member
"m" #'omnisharp-navigate-to-solution-member
"M" #'omnisharp-navigate-to-solution-file-then-file-member
"F" #'omnisharp-navigate-to-solution-file
"r" #'omnisharp-navigate-to-region
"ti" #'omnisharp-current-type-information
"td" #'omnisharp-current-type-documentation)
(:prefix "t"
"r" (λ! (omnisharp-unit-test "fixture"))
"s" (λ! (omnisharp-unit-test "single"))
"a" (λ! (omnisharp-unit-test "all")))))
(def-package! shader-mode :mode "\\.shader$") ; unity shaders
(when (featurep! +unity)
;; `shader-mode' --- unity shaders
(add-to-list 'auto-mode-alist '("\\.shader$" . shader-mode))
(def-project-mode! +csharp-unity-mode
:modes (csharp-mode shader-mode)
:files (and "Assets" "Library/MonoManager.asset" "Library/ScriptMapper")))

View file

@ -0,0 +1,7 @@
;; -*- lexical-binding: t; no-byte-compile: t; -*-
;;; lang/csharp/doctor.el
(require 'omnisharp)
(let ((omnisharp-bin (or omnisharp-server-executable-path (omnisharp--server-installation-path t))))
(unless (file-exists-p omnisharp-bin)
(warn! "Omnisharp server isn't installed, completion won't work")))

View file

@ -3,5 +3,6 @@
(package! csharp-mode)
(package! omnisharp)
(package! shader-mode)
(when (featurep! +unity)
(package! shader-mode))

View file

@ -1,11 +0,0 @@
#!/usr/bin/env bash
source VARS
#
echo "Setting up C# (omnisharp)"
git-repo "https://github.com/OmniSharp/omnisharp-server" omnisharp
cd omnisharp && xbuild
mv omnisharp/bin/Debug/OmniSharp.exe ./OmniSharp.exe
rm -rf omnisharp

View file

@ -1,51 +1,40 @@
;;; lang/data/config.el -*- lexical-binding: t; -*-
(push '("/sxhkdrc" . conf-mode) auto-mode-alist)
;; Built in plugins
(add-to-list 'auto-mode-alist '("/sxhkdrc\\'" . conf-mode))
(add-to-list 'auto-mode-alist '("\\.\\(?:hex\\|nes\\)\\'" . hexl-mode))
(add-to-list 'auto-mode-alist '("\\.plist\\'" . nxml-mode))
(after! nxml-mode
(set-company-backend! 'nxml-mode '(company-nxml company-yasnippet)))
(def-package! nxml-mode
:mode "\\.plist$"
:config
(set! :company-backend 'nxml-mode '(company-nxml company-yasnippet)))
;;
;; Third-party plugins
;; `csv-mode'
(map! :after csv-mode
:localleader
:map csv-mode-map
"a" #'csv-align-fields
"u" #'csv-unalign-fields
"s" #'csv-sort-fields
"S" #'csv-sort-numeric-fields
"k" #'csv-kill-fields
"t" #'csv-transpose)
(def-package! toml-mode :mode "\\.toml$")
(def-package! yaml-mode :mode "\\.ya?ml$")
(def-package! graphql-mode
:mode "\\.gql\\'")
(def-package! json-mode
:mode "\\.js\\(on\\|[hl]int\\(rc\\)?\\)$"
:mode "\\.js\\(?:on\\|[hl]int\\(?:rc\\)?\\)\\'"
:config
(set! :electric 'json-mode :chars '(?\n ?: ?{ ?})))
(def-package! vimrc-mode
:mode "/\\.?g?vimrc$"
:mode "\\.vim$"
:mode "\\.?vimperatorrc$"
:mode "\\.vimp$")
(def-package! dockerfile-mode
:mode "/Dockerfile$")
;; For ROM hacking or debugging
(def-package! hexl
:mode ("\\.hex$" . hexl-mode)
:mode ("\\.nes$" . hexl-mode))
(set-electric! 'json-mode :chars '(?\n ?: ?{ ?})))
;;
;; Frameworks
;;
(def-project-mode! +data-ansible-mode
:modes (yaml-mode)
:files "roles/")
(def-project-mode! +data-vagrant-mode
:files "Vagrantfile")
:files ("Vagrantfile"))

View file

@ -1,9 +1,9 @@
;; -*- no-byte-compile: t; -*-
;;; lang/data/packages.el
(package! dockerfile-mode)
(package! graphql-mode)
(package! json-mode)
(package! toml-mode)
(package! vimrc-mode)
(package! yaml-mode)
(package! csv-mode)
(package! dhall-mode)

View file

@ -1,37 +1,57 @@
;;; lang/elixir/config.el -*- lexical-binding: t; -*-
(def-package! elixir-mode
:mode "\\.exs?$"
:mode "\\.elixir2$"
:defer t
:init
;; Disable default smartparens config. There are too many pairs; we only want
;; a subset of them (defined below).
(provide 'smartparens-elixir)
:config
;; disable standard config; more disruptive than it needs to be
(dolist (beg '("fn" "do" "def" "defp" "defmodule" "if" "unless" "case" "receive"))
(sp-local-pair 'elixir-mode beg nil :actions :rem))
;; only complete the basics
(sp-with-modes 'elixir-mode
(sp-local-pair "do" "end" :when '(("RET" "<evil-ret>")) :post-handlers '("||\n[i]"))
(sp-local-pair "do " " end")
(sp-local-pair "fn " " end")))
(set-pretty-symbols! 'elixir-mode
;; Functional
:def "def"
:lambda "fn"
;; :src_block "do"
;; :src_block_end "end"
;; Flow
:not "!"
:in "in" :not-in "not in"
:and "and" :or "or"
:for "for"
:return "return" :yield "use")
;; ...and only complete the basics
(after! smartparens
(sp-with-modes 'elixir-mode
(sp-local-pair "do" "end"
:when '(("RET" "<evil-ret>"))
:unless '(sp-in-comment-p sp-in-string-p)
:post-handlers '("||\n[i]"))
(sp-local-pair "do " " end" :unless '(sp-in-comment-p sp-in-string-p))
(sp-local-pair "fn " " end" :unless '(sp-in-comment-p sp-in-string-p))))
(def-package! alchemist-company
:when (featurep! :completion company)
:commands alchemist-company
:init
(set-company-backend! 'elixir-mode '(alchemist-company company-yasnippet))
:config
;; Alchemist doesn't use hook symbols to add these backends, so we have to
;; use the entire closure to get rid of it.
(let ((fn (byte-compile (lambda () (add-to-list (make-local-variable 'company-backends) 'alchemist-company)))))
(remove-hook 'alchemist-mode-hook fn)
(remove-hook 'alchemist-iex-mode-hook fn)))
(def-package! flycheck-credo
:when (featurep! :tools flycheck)
:config (flycheck-credo-setup)))
(def-package! alchemist
:after elixir-mode
:hook (elixir-mode . alchemist-mode)
:config
(set! :jump 'elixir-mode
(set-lookup-handlers! 'elixir-mode
:definition #'alchemist-goto-definition-at-point
:documentation #'alchemist-help-search-at-point)
(set! :eval 'elixir-mode #'alchemist-eval-region))
(def-package! alchemist-company
:when (featurep! :completion company)
:after elixir-mode
:config
;; Let Doom handle this
(let ((fn (byte-compile (lambda () (add-to-list (make-local-variable 'company-backends) 'alchemist-company)))))
(remove-hook 'alchemist-mode-hook fn)
(remove-hook 'alchemist-iex-mode-hook fn))
(set! :company-backend 'elixir-mode '(alchemist-company company-yasnippet)))
(set-eval-handler! 'elixir-mode #'alchemist-eval-region)
(set-repl-handler! 'elixir-mode #'alchemist-iex-project-run))

View file

@ -4,4 +4,5 @@
;; +elixir.el
(package! elixir-mode)
(package! alchemist)
(package! ac-alchemist)
(when (featurep! :tools flycheck)
(package! flycheck-credo))

View file

@ -1,14 +1,25 @@
;;; lang/elm/config.el -*- lexical-binding: t; -*-
(def-package! elm-mode
:mode "\\.elm$"
:config
(add-hook! 'elm-mode-hook #'(flycheck-mode rainbow-delimiters-mode))
(set! :company-backend 'elm-mode '(company-elm))
(setq elm-format-on-save t))
;; `elm-mode'
(setq elm-format-on-save t)
(after! elm-mode
(add-hook 'elm-mode-hook #'rainbow-delimiters-mode)
(set-company-backend! 'elm-mode 'company-elm)
(set-repl-handler! 'elm-mode #'run-elm-interactive)
(set-pretty-symbols! 'elm-mode
:null "null"
:true "true" :false "false"
:int "Int" :str "String"
:float "Float"
:bool "Bool"
:not "not"
:and "&&" :or "||"))
(def-package! flycheck-elm
:after (:all flycheck elm-mode)
:hook (flycheck-mode . flycheck-elm-setup))
:when (featurep! :tools flycheck)
:after elm-mode
:config (add-to-list 'flycheck-checkers 'elm nil #'eq))

View file

@ -1,6 +1,7 @@
;; -*- no-byte-compile: t; -*-
;;; lang/elm/packages.el
(package! flycheck-elm)
(package! elm-mode)
(when (featurep! :tools flycheck)
(package! flycheck-elm))

View file

@ -1,7 +1,86 @@
;;; lang/emacs-lisp/autoload.el -*- lexical-binding: t; -*-
;;
;; Library
;;;###autoload
(defun +emacs-lisp/repl ()
(defun +emacs-lisp-eval (beg end)
"Evaluate a region and print it to the echo area (if one line long), otherwise
to a pop up buffer."
(require 'pp)
(let ((result
(let ((debug-on-error t)
(doom--current-module (ignore-errors (doom-module-from-path buffer-file-name))))
(eval (read
(concat "(progn "
(buffer-substring-no-properties beg end)
"\n)"))
t)))
(buf (get-buffer-create "*doom eval*"))
(inhibit-read-only t))
(with-current-buffer buf
(read-only-mode +1)
(erase-buffer)
(setq-local scroll-margin 0)
(let (emacs-lisp-mode-hook)
(emacs-lisp-mode))
(prin1 result buf)
(pp-buffer)
(let ((lines (count-lines (point-min) (point-max))))
(if (> lines 1)
(save-selected-window
(pop-to-buffer buf)
(with-current-buffer buf
(goto-char (point-min))))
(message "%s" (buffer-substring (point-min) (point-max)))
(kill-buffer buf))))))
(defvar +emacs-lisp--face nil)
;;;###autoload
(defun +emacs-lisp-highlight-vars-and-faces (end)
"Match defined variables and functions.
Functions are differentiated into special forms, built-in functions and
library/userland functions"
(catch 'matcher
(while (re-search-forward "\\_<.+?\\_>" end t)
(unless (save-excursion
(let ((ppss (syntax-ppss)))
(or (nth 3 ppss) (nth 4 ppss))))
(let ((symbol (intern-soft (match-string-no-properties 0))))
(and (cond ((null symbol) nil)
((eq symbol t) nil)
((special-variable-p symbol)
(setq +emacs-lisp--face 'font-lock-variable-name-face))
((and (fboundp symbol)
(eq (char-before (match-beginning 0)) ?\())
(let ((unaliased (indirect-function symbol)))
(unless (or (macrop unaliased)
(special-form-p unaliased))
(let (unadvised)
(while (not (eq (setq unadvised (ad-get-orig-definition unaliased))
(setq unaliased (indirect-function unadvised)))))
unaliased)
(setq +emacs-lisp--face
(if (subrp unaliased)
'font-lock-constant-face
'font-lock-function-name-face))))))
(throw 'matcher t)))))
nil))
;; `+emacs-lisp-highlight-vars-and-faces' is a potentially expensive function
;; and should be byte-compiled, no matter what, to ensure it runs as fast as
;; possible:
(when (not (byte-code-function-p (symbol-function '+emacs-lisp-highlight-vars-and-faces)))
(with-no-warnings
(byte-compile #'+emacs-lisp-highlight-vars-and-faces)))
;;
;; Commands
;;;###autoload
(defun +emacs-lisp/open-repl ()
"Open the Emacs Lisp REPL (`ielm')."
(interactive)
(pop-to-buffer
@ -11,25 +90,44 @@
(bury-buffer buf)
buf)))))
;;
;; Hooks
;;;###autoload
(defun +emacs-lisp-eval (beg end)
"Evaluate a region and print it to the echo area (if one line long), otherwise
to a pop up buffer."
(require 'pp)
(let ((result (eval (read (concat "(progn " (buffer-substring-no-properties beg end) "\n)"))))
(buf (get-buffer-create "*doom eval*"))
(inhibit-read-only t)
lines)
(with-current-buffer buf
(read-only-mode +1)
(erase-buffer)
(setq-local scroll-margin 0)
(emacs-lisp-mode)
(prin1 result buf)
(pp-buffer)
(setq lines (count-lines (point-min) (point-max)))
(goto-char (point-min))
(if (> lines 1)
(doom-popup-buffer buf)
(message "%s" (buffer-substring (point-min) (point-max)))
(kill-buffer buf)))))
(defun +emacs-lisp|extend-imenu ()
"Improve imenu support with better expression regexps and Doom-specific forms."
(setq imenu-generic-expression
'(("Evil commands" "^\\s-*(evil-define-\\(?:command\\|operator\\|motion\\) +\\(\\_<[^ ()\n]+\\_>\\)" 1)
("Unit tests" "^\\s-*(\\(?:ert-deftest\\|describe\\) +\"\\([^\")]+\\)\"" 1)
("Package" "^\\s-*(\\(?:def-\\)?package! +\\(\\_<[^ ()\n]+\\_>\\)" 1)
("Package" "^\\s-*;;;###package\\s-+\\(\\_<[^ ()\n]+\\_>\\)$" 1)
("Major modes" "^\\s-*(define-derived-mode +\\([^ ()\n]+\\)" 1)
("Modelines" "^\\s-*(def-modeline! +\\([^ ()\n]+\\)" 1)
("Modeline segments" "^\\s-*(def-modeline-segment! +\\([^ ()\n]+\\)" 1)
("Advice" "^\\s-*(def\\(?:\\(?:ine-\\)?advice\\))")
("Modes" "^\\s-*(define-\\(?:global\\(?:ized\\)?-minor\\|generic\\|minor\\)-mode +\\([^ ()\n]+\\)" 1)
("Macros" "^\\s-*(\\(?:cl-\\)?def\\(?:ine-compile-macro\\|macro\\) +\\([^ )\n]+\\)" 1)
("Inline functions" "\\s-*(\\(?:cl-\\)?defsubst +\\([^ )\n]+\\)" 1)
("Functions" "^\\s-*(\\(?:cl-\\)?def\\(?:un\\|un\\*\\|method\\|generic\\|-memoized!\\) +\\([^ ,)\n]+\\)" 1)
("Variables" "^\\s-*(\\(def\\(?:c\\(?:onst\\(?:ant\\)?\\|ustom\\)\\|ine-symbol-macro\\|parameter\\|var\\(?:-local\\)?\\)\\)\\s-+\\(\\(?:\\sw\\|\\s_\\|\\\\.\\)+\\)" 2)
("Types" "^\\s-*(\\(cl-def\\(?:struct\\|type\\)\\|def\\(?:class\\|face\\|group\\|ine-\\(?:condition\\|error\\|widget\\)\\|package\\|struct\\|t\\(?:\\(?:hem\\|yp\\)e\\)\\)\\)\\s-+'?\\(\\(?:\\sw\\|\\s_\\|\\\\.\\)+\\)" 2))))
;;;###autoload
(defun +emacs-lisp|disable-flycheck-maybe ()
"Disable flycheck-mode if in emacs.d."
(when (and (bound-and-true-p flycheck-mode)
(eq major-mode 'emacs-lisp-mode)
(or (not buffer-file-name)
(cl-loop for dir in (list doom-emacs-dir doom-private-dir)
if (file-in-directory-p buffer-file-name dir)
return t)))
(flycheck-mode -1)))
;;;###autoload
(defun +emacs-lisp-lookup-documentation (thing)
"Lookup THING with `helpful-variable' if it's a variable, `helpful-callable'
if it's callable, `apropos' otherwise."
(if thing
(doom/describe-symbol thing)
(call-interactively #'doom/describe-symbol)))

View file

@ -1,12 +1,32 @@
;;; lang/emacs-lisp/config.el -*- lexical-binding: t; -*-
(def-package! elisp-mode ; built-in
:mode ("/Cask$" . emacs-lisp-mode)
(defvar +emacs-lisp-enable-extra-fontification t
"If non-nil, highlight special forms, and defined functions and variables.")
(defvar +emacs-lisp-outline-regexp "[ \t]*;;;;* [^ \t\n]"
"Regexp to use for `outline-regexp' in `emacs-lisp-mode'.
This marks a foldable marker for `outline-minor-mode' in elisp buffers.")
;; `elisp-mode' is loaded at startup. In order to lazy load its config we need
;; to pretend it isn't loaded
(defer-feature! elisp-mode emacs-lisp-mode)
;;
;; Config
(def-package! elisp-mode
:mode ("\\.Cask\\'" . emacs-lisp-mode)
:config
(set! :repl 'emacs-lisp-mode #'+emacs-lisp/repl)
(set! :eval 'emacs-lisp-mode #'+emacs-lisp-eval)
(set! :jump 'emacs-lisp-mode :documentation #'describe-symbol)
(set! :rotate 'emacs-lisp-mode
(set-repl-handler! 'emacs-lisp-mode #'+emacs-lisp/open-repl)
(set-eval-handler! 'emacs-lisp-mode #'+emacs-lisp-eval)
(set-lookup-handlers! 'emacs-lisp-mode
:definition #'elisp-def
:documentation #'+emacs-lisp-lookup-documentation)
(set-docsets! 'emacs-lisp-mode "Emacs Lisp")
(set-pretty-symbols! 'emacs-lisp-mode :lambda "lambda")
(set-rotate-patterns! 'emacs-lisp-mode
:symbols '(("t" "nil")
("let" "let*")
("when" "unless")
@ -15,110 +35,111 @@
("add-hook" "remove-hook")
("add-hook!" "remove-hook!")))
(setq-hook! 'emacs-lisp-mode-hook
;; shorter name in modeline
mode-name "Elisp"
;; Don't treat autoloads or sexp openers as outline headers, we have
;; hideshow for that.
outline-regexp +emacs-lisp-outline-regexp)
;; variable-width indentation is superior in elisp
(add-to-list 'doom-detect-indentation-excluded-modes 'emacs-lisp-mode nil #'eq)
(add-hook! 'emacs-lisp-mode-hook
#'(;; 3rd-party functionality
eldoc-mode auto-compile-on-save-mode doom|enable-delete-trailing-whitespace
;; fontification
rainbow-delimiters-mode highlight-quoted-mode highlight-numbers-mode +emacs-lisp|extra-fontification
auto-compile-on-save-mode
outline-minor-mode
;; initialization
+emacs-lisp|init-imenu +emacs-lisp|init-flycheck))
+emacs-lisp|extend-imenu))
;;
(defun +emacs-lisp|extra-fontification ()
"Display lambda as a smybol and fontify doom module functions."
(font-lock-add-keywords
nil `(;; Display "lambda" as λ
("(\\(lambda\\)" (1 (ignore (compose-region (match-beginning 1) (match-end 1) #'decompose-region))))
;; Highlight doom/module functions
("\\(^\\|\\s-\\|,\\)(\\(\\(doom\\|\\+\\)[^) ]+\\)[) \n]" (2 font-lock-keyword-face)))))
;; Flycheck produces a *lot* of false positives in emacs configs, so disable
;; it when you're editing them
(add-hook 'flycheck-mode-hook #'+emacs-lisp|disable-flycheck-maybe)
(defun +emacs-lisp|init-imenu ()
"Improve imenu support with better expression regexps and Doom-specific forms."
(setq imenu-generic-expression
'(("Evil Commands" "^\\s-*(evil-define-\\(?:command\\|operator\\|motion\\) +\\(\\_<[^ ()\n]+\\_>\\)" 1)
("Package" "^\\s-*(\\(?:def-\\)?package! +\\(\\_<[^ ()\n]+\\_>\\)" 1)
("Settings" "^\\s-*(def-setting! +\\([^ ()\n]+\\)" 1)
("Modelines" "^\\s-*(def-modeline! +\\([^ ()\n]+\\)" 1)
("Modeline Segments" "^\\s-*(def-modeline-segment! +\\([^ ()\n]+\\)" 1)
("Advice" "^\\s-*(def\\(?:\\(?:ine-\\)?advice\\))")
("Modes" "^\\s-*(define-\\(?:global\\(?:ized\\)?-minor\\|generic\\|minor\\)-mode +\\([^ ()\n]+\\)" 1)
("Macros" "^\\s-*(\\(?:cl-\\)?def\\(?:ine-compile-macro\\|macro\\) +\\([^ )\n]+\\)" 1)
("Inline Functions" "\\s-*(\\(?:cl-\\)?defsubst +\\([^ )\n]+\\)" 1)
("Functions" "^\\s-*(\\(?:cl-\\)?def\\(?:un\\|un\\*\\|method\\|generic\\|-memoized!\\) +\\([^ ,)\n]+\\)" 1)
("Variables" "^\\s-*(\\(def\\(?:c\\(?:onst\\(?:ant\\)?\\|ustom\\)\\|ine-symbol-macro\\|parameter\\)\\)\\s-+\\(\\(?:\\sw\\|\\s_\\|\\\\.\\)+\\)" 2)
("Variables" "^\\s-*(defvar\\(?:-local\\)?\\s-+\\(\\(?:\\sw\\|\\s_\\|\\\\.\\)+\\)[[:space:]\n]+[^)]" 1)
("Types" "^\\s-*(\\(cl-def\\(?:struct\\|type\\)\\|def\\(?:class\\|face\\|group\\|ine-\\(?:condition\\|error\\|widget\\)\\|package\\|struct\\|t\\(?:\\(?:hem\\|yp\\)e\\)\\)\\)\\s-+'?\\(\\(?:\\sw\\|\\s_\\|\\\\.\\)+\\)" 2))))
;; Special fontification for elisp
(font-lock-add-keywords
'emacs-lisp-mode
(append `(;; custom Doom cookies
("^;;;###\\(autodef\\|if\\|package\\)[ \n]" (1 font-lock-warning-face t)))
;; highlight defined, special variables & functions
(when +emacs-lisp-enable-extra-fontification
`((+emacs-lisp-highlight-vars-and-faces . +emacs-lisp--face)))))
(defun +emacs-lisp|init-flycheck ()
"Initialize flycheck-mode if not in emacs.d."
(when (and buffer-file-name
(not (file-in-directory-p buffer-file-name doom-emacs-dir)))
(flycheck-mode +1))))
(add-hook! 'emacs-lisp-mode-hook #'(rainbow-delimiters-mode highlight-quoted-mode))
;; Recenter window after following definition
(advice-add #'elisp-def :after #'doom*recenter)
(map! :localleader
:map emacs-lisp-mode-map
"e" #'macrostep-expand))
;;
;; Plugins
;;
;; Packages
(def-package! auto-compile
:commands auto-compile-on-save-mode
:config
(setq auto-compile-display-buffer nil
auto-compile-use-mode-line nil))
;; `auto-compile'
(setq auto-compile-display-buffer nil
auto-compile-use-mode-line nil)
(def-package! highlight-quoted
:commands highlight-quoted-mode)
;; `macrostep'
(when (featurep! :feature evil)
(after! macrostep
(evil-define-key* 'normal macrostep-keymap
[return] #'macrostep-expand
"e" #'macrostep-expand
"u" #'macrostep-collapse
"c" #'macrostep-collapse
[tab] #'macrostep-next-macro
"\C-n" #'macrostep-next-macro
"J" #'macrostep-next-macro
[backtab] #'macrostep-prev-macro
"K" #'macrostep-prev-macro
"\C-p" #'macrostep-prev-macro
"q" #'macrostep-collapse-all
"C" #'macrostep-collapse-all)
;; `evil-normalize-keymaps' seems to be required for macrostep or it won't
;; apply for the very first invocation
(add-hook 'macrostep-mode-hook #'evil-normalize-keymaps)))
(def-package! slime
:defer t
:config
(setq inferior-lisp-program "clisp")
(require 'slime-fuzzy))
(def-package! macrostep
:commands macrostep-expand
:config
(map! :map macrostep-keymap
:n "RET" #'macrostep-expand
:n "e" #'macrostep-expand
:n "u" #'macrostep-collapse
:n "c" #'macrostep-collapse
:n "TAB" #'macrostep-next-macro
:n "n" #'macrostep-next-macro
:n "J" #'macrostep-next-macro
:n "S-TAB" #'macrostep-prev-macro
:n "K" #'macrostep-prev-macro
:n "p" #'macrostep-prev-macro
:n "q" #'macrostep-collapse-all
:n "C" #'macrostep-collapse-all)
;; `evil-normalize-keymaps' seems to be required for macrostep or it won't
;; apply for the very first invocation
(add-hook 'macrostep-mode-hook #'evil-normalize-keymaps))
;; `overseer'
(autoload 'overseer-test "overseer" nil t)
(remove-hook 'emacs-lisp-mode-hook 'overseer-enable-mode)
(def-package! flycheck-cask
:when (featurep! :feature syntax-checker)
:commands flycheck-cask-setup
:when (featurep! :tools flycheck)
:defer t
:init
(add-hook! 'emacs-lisp-hook
(add-hook! 'emacs-lisp-mode-hook
(add-hook 'flycheck-mode-hook #'flycheck-cask-setup nil t)))
(def-package! overseer
:commands overseer-test
:init (set! :popup "*overseer*" :size 12))
(def-package! elisp-demos
:defer t
:init
(advice-add 'describe-function-1 :after #'elisp-demos-advice-describe-function-1)
(advice-add 'helpful-update :after #'elisp-demos-advice-helpful-update))
;;
;;
;;
;; Project modes
(def-project-mode! +emacs-lisp-ert-mode
:modes (emacs-lisp-mode)
:match "/test[/-].+\\.el$"
:add-hooks (overseer-enable-mode))
(associate! buttercup-minor-mode
:modes (emacs-lisp-mode)
:match "/test[/-].+\\.el$")
(after! buttercup
(set-yas-minor-mode! 'buttercup-minor-mode))

View file

@ -1,11 +1,14 @@
;; -*- no-byte-compile: t; -*-
;;; lang/emacs-lisp/packages.el
(package! elisp-mode :built-in t)
(package! auto-compile)
(package! highlight-quoted)
(package! macrostep)
(package! overseer)
(package! slime)
(package! elisp-def)
(package! elisp-demos)
(when (featurep! :feature syntax-checker)
(when (featurep! :tools flycheck)
(package! flycheck-cask))

View file

@ -0,0 +1,25 @@
;;; lang/erlang/config.el -*- lexical-binding: t; -*-
(def-package! erlang
:mode ("\\.erlang$" . erlang-mode)
:mode ("/rebar\\.config\\(?:\\.script\\)?$" . erlang-mode)
:mode ("/\\(?:app\\|sys\\)\\.config$" . erlang-mode))
(def-package! flycheck-rebar3
:when (featurep! :tools flycheck)
:after flycheck
:config (flycheck-rebar3-setup))
(def-package! ivy-erlang-complete
:when (featurep! :completion ivy)
:hook (erlang-mode . ivy-erlang-complete-init)
:config
(add-hook! 'erlang-mode-hook
(add-hook 'after-save-hook #'ivy-erlang-complete-reparse nil t)))
(def-package! company-erlang
:when (featurep! :completion company)
:hook (erlang-mode . company-erlang-init))

View file

@ -0,0 +1,13 @@
;; -*- no-byte-compile: t; -*-
;;; private/erlang/packages.el
(package! erlang)
(when (featurep! :tools flycheck)
(package! flycheck-rebar3))
(when (featurep! :completion ivy)
(package! ivy-erlang-complete))
(when (featurep! :completion company)
(package! company-erlang))

View file

@ -0,0 +1,50 @@
#+TITLE: :lang ess
This module adds support for various statistics languages, including R, S-Plus,
SAS, Julia and Stata.
* Table of Contents :TOC:
- [[Appendix][Appendix]]
- [[Keybindings][Keybindings]]
* Appendix
** Keybindings
*** :map ess-doc-map
| key | command |
|-----+----------------------------|
| "h" | ess-display-help-on-object |
| "p" | ess-R-dv-pprint |
| "t" | ess-R-dv-ctable |
*** :map ess-mode-map
| key | command |
|--------------+-----------------------|
| "<s-return>" | ess-eval-line |
| "<up>" | comint-next-input |
| "<down>" | comint-previous-input |
**** :localleader
| state | key | command |
|-------+-------------+---------------------------------------------------|
| :nv | "," | ess-eval-region-or-function-or-paragraph-and-step |
| :n | "'" | R |
| :n | "<tab>" | ess-switch-to-inferior-or-script-buffer |
| :n | "<backtab>" | ess-switch-process |
| :n | "B" | ess-eval-buffer-and-go |
| :n | "b" | ess-eval-buffer |
| :nv | "d" | ess-eval-region-or-line-and-step |
| :n | "D" | ess-eval-function-or-paragraph-and-step |
| :n | "L" | ess-eval-line-and-go |
| :n | "l" | ess-eval-line |
| :nv | "R" | ess-eval-region-and-go |
| :nv | "r" | ess-eval-region |
| :n | "F" | ess-eval-function-and-go |
| :n | "f" | ess-eval-function |
| :n | "h" | ess-doc-map |
| :n | "x" | ess-extra-map |
| :n | "p" | ess-r-package-dev-map |
| :n | "v" | ess-dev-map |
| :n | "cC" | ess-eval-chunk-and-go |
| :n | "cc" | ess-eval-chunk |
| :n | "cd" | ess-eval-chunk-and-step |
| :n | "cm" | ess-noweb-mark-chunk |
| :n | "cp" | ess-noweb-previous-chunk |
| :n | "cn" | ess-noweb-next-chunk |

View file

@ -0,0 +1,11 @@
;;; lang/ess/autoload.el -*- lexical-binding: t; -*-
;;;###autoload
(defun +ess-repl-buffer (&optional start-args)
"Returns an R/Julia REPL buffer."
(interactive "P")
(pcase major-mode
('ess-r-mode (run-ess-r start-args))
((or 'julia-mode 'ess-julia-mode) (run-julia start-args))
(_ (inferior-ess nil nil t)))
(current-buffer))

View file

@ -0,0 +1,72 @@
;;; lang/ess/config.el -*- lexical-binding: t; -*-
(def-package! ess
:commands (stata SAS)
:init
(setq ess-smart-S-assign-key nil)
(unless (featurep! :lang julia)
(add-to-list 'auto-mode-alist '("\\.jl\\'" . ess-julia-mode)))
:config
(setq ess-offset-continued 'straight
ess-expression-offset 2
ess-use-flymake (not (featurep! :tools flycheck))
ess-nuke-trailing-whitespace-p t
ess-default-style 'DEFAULT
ess-history-directory (expand-file-name "ess-history/" doom-cache-dir))
(set-repl-handler! '(ess-r-mode ess-julia-mode) #'+ess-repl-buffer)
(set-lookup-handlers! '(ess-r-mode ess-julia-mode)
:documentation #'ess-display-help-on-object)
(set-evil-initial-state! 'ess-r-help-mode 'normal)
(set-eval-handler! 'ess-help-mode #'ess-eval-region-and-go)
(set-eval-handler! 'ess-r-help-mode #'ess-eval-region-and-go)
(map! (:after ess-help
:map ess-help-mode-map
:n "q" #'kill-this-buffer
:n "Q" #'ess-kill-buffer-and-go
:n "K" #'ess-display-help-on-object
:n "go" #'ess-display-help-in-browser
:n "gO" #'ess-display-help-apropos
:n "gv" #'ess-display-vignettes
:m "]]" #'ess-skip-to-next-section
:m "[[" #'ess-skip-to-previous-section
:map ess-doc-map
"h" #'ess-display-help-on-object
"p" #'ess-R-dv-pprint
"t" #'ess-R-dv-ctable
[C-return] #'ess-eval-line
[up] #'comint-next-input
[down] #'comint-previous-input)
:localleader
:map ess-mode-map
"," #'ess-eval-region-or-function-or-paragraph-and-step
"'" #'R
[tab] #'ess-switch-to-inferior-or-script-buffer
[backtab] #'ess-switch-process
;; REPL
"B" #'ess-eval-buffer-and-go
"b" #'ess-eval-buffer
"d" #'ess-eval-region-or-line-and-step
"D" #'ess-eval-function-or-paragraph-and-step
"L" #'ess-eval-line-and-go
"l" #'ess-eval-line
"R" #'ess-eval-region-and-go
"r" #'ess-eval-region
"F" #'ess-eval-function-and-go
"f" #'ess-eval-function
;; predefined keymaps
"h" 'ess-doc-map
"x" 'ess-extra-map
"p" 'ess-r-package-dev-map
"v" 'ess-dev-map
;; noweb
:prefix "c"
"C" #'ess-eval-chunk-and-go
"c" #'ess-eval-chunk
"d" #'ess-eval-chunk-and-step
"m" #'ess-noweb-mark-chunk
"p" #'ess-noweb-previous-chunk
"n" #'ess-noweb-next-chunk))

View file

@ -0,0 +1,5 @@
;; -*- no-byte-compile: t; -*-
;;; lang/ess/packages.el
(package! ess)
(package! ess-R-data-view)

View file

@ -1,5 +1,20 @@
#+TITLE: :lang go
#+TITLE: lang/go
#+DATE: January 16, 2017
#+SINCE: v2.0
#+STARTUP: inlineimages
* Table of Contents :TOC:
- [[Description][Description]]
- [[Module Flags][Module Flags]]
- [[Plugins][Plugins]]
- [[Prerequisites][Prerequisites]]
- [[Go][Go]]
- [[Dependencies][Dependencies]]
- [[Features][Features]]
- [[Configuration][Configuration]]
- [[Troubleshooting][Troubleshooting]]
* Description
This module adds [[https://golang.org][Go]] support.
+ Code completion (~gocode~)
@ -12,29 +27,28 @@ This module adds [[https://golang.org][Go]] support.
+ [[../../feature/file-templates/templates/go-mode][File templates]]
+ [[https://github.com/hlissner/emacs-snippets/tree/master/go-mode][Snippets]]
#+begin_quote
I have mixed feelings about Go. It's a decent compromise between C and higher-level languages, is pleasantly straight-forward and elegant, but lacks /native/ support for luxuries I miss from other languages, like generics, optional arguments, and function overloading. You've got to learn to love ~interface{}~.
** Module Flags
This module provides no flags.
Still, Go is a remarkably useful (and fast!) companion for a variety of small-to-medium backend web and CLI projects.
#+end_quote
** Plugins
+ [[https://github.com/dominikh/go-mode.el][go-mode]]
+ [[https://github.com/syohex/emacs-go-eldoc][go-eldoc]]
+ [[https://github.com/dominikh/go-mode.el][go-guru]]
+ [[https://github.com/manute/gorepl-mode][gorepl-mode]]
+ [[https://github.com/mdempsky/gocode][company-go]]*
* Table of Contents :TOC:
- [[#install][Install]]
- [[#go][Go]]
- [[#dependencies][Dependencies]]
* Install
* Prerequisites
** Go
To get started with Go, you need the ~go~ tool:
*** MacOS
#+BEGIN_SRC sh :tangle (if (doom-system-os 'macos) "yes")
#+BEGIN_SRC bash
brew install go
#+END_SRC
*** Arch Linux
#+BEGIN_SRC sh :dir /sudo:: :tangle (if (doom-system-os 'arch) "yes")
sudo pacman --needed --noconfirm -S go
#+BEGIN_SRC bash
sudo pacman -S go
#+END_SRC
** Dependencies
@ -42,19 +56,24 @@ This module requires a valid ~GOPATH~, and the following Go packages:
+ ~gocode~ (for code completion & eldoc support)
+ ~godoc~ (for documentation lookup)
+ ~goimports~ (for auto-formatting code on save and fixing imports)
+ ~gorename~ (for extra refactoring commands)
+ ~gore~ (for the REPL)
+ ~guru~ (for code navigation & refactoring commands)
+ ~goimports~ (optional: for auto-formatting code on save & fixing imports)
#+BEGIN_SRC sh
export GOPATH=~/work/go
go get -u github.com/motemen/gore
go get -u github.com/nsf/gocode
go get -u github.com/motemen/gore/cmd/gore
go get -u github.com/mdempsky/gocode
go get -u golang.org/x/tools/cmd/godoc
go get -u golang.org/x/tools/cmd/goimports
go get -u golang.org/x/tools/cmd/gorename
go get -u golang.org/x/tools/cmd/guru
#+END_SRC
* TODO Features
* TODO Configuration
* TODO Troubleshooting

View file

@ -2,12 +2,12 @@
;;
;; Tests
;;
(defvar +go-test-last nil
"The last test run.")
(defun +go--run-tests (args)
(require 'async)
(save-selected-window
(async-shell-command (concat "go test " args))))
@ -37,3 +37,10 @@
(+go--run-tests (concat "-run" "='" (match-string-no-properties 2) "'")))
(error "Must be in a _test.go file")))
;;;###autoload
(defun +go/play-buffer-or-region (&optional beg end)
"TODO"
(interactive "r")
(if (use-region-p)
(go-play-region beg end)
(go-play-buffer)))

View file

@ -1,95 +1,66 @@
;;; lang/go/config.el -*- lexical-binding: t; -*-
(def-package! go-mode
:mode "\\.go$"
:interpreter "go"
:config
(add-hook 'go-mode-hook #'flycheck-mode)
;;
;; Packages
(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! :repl 'go-mode #'gorepl-run)
(set! :jump 'go-mode
(after! go-mode
(set-docsets! 'go-mode "Go")
(set-repl-handler! 'go-mode #'gorepl-run)
(set-lookup-handlers! '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: ")
;; Redefines default formatter to *not* use goimports if reformatting a
;; region; as it doesn't play well with partial code.
(set-formatter! 'gofmt
'(("%s" (if (or +format-region-p
(not (executable-find "goimports")))
"gofmt"
"goimports"))))
(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)))
(if (featurep! +lsp)
(add-hook 'go-mode-hook #'lsp!)
(add-hook 'go-mode-hook #'go-eldoc-setup))
(map! :map go-mode-map
: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))
(def-package! go-eldoc
:hook (go-mode . go-eldoc-setup))
(def-package! go-guru
:commands (go-guru-describe go-guru-freevars go-guru-implements go-guru-peers
go-guru-referrers go-guru-definition go-guru-pointsto
go-guru-callstack go-guru-whicherrs go-guru-callers go-guru-callees
go-guru-expand-region)
:config
(unless (executable-find "guru")
(warn "go-mode: couldn't find guru, refactoring commands won't work")))
"e" #'+go/play-buffer-or-region
"i" #'go-goto-imports ; Go to imports
(:prefix ("h" . "help")
"." #'godoc-at-point ; Lookup in godoc
"d" #'go-guru-describe ; Describe this
"v" #'go-guru-freevars ; List free variables
"i" #'go-guru-implements ; Implements relations for package types
"p" #'go-guru-peers ; List peers for channel
"P" #'go-guru-pointsto ; What does this point to
"r" #'go-guru-referrers ; List references to object
"e" #'go-guru-whicherrs ; Which errors
"w" #'go-guru-what ; What query
"c" #'go-guru-callers ; Show callers of this function
"C" #'go-guru-callees) ; Show callees of this function
(:prefix ("ri" . "imports")
"a" #'go-import-add
"r" #'go-remove-unused-imports)
(:prefix ( "b" . "build")
:desc "go run ." "r" (λ! (compile "go run ."))
:desc "go build" "b" (λ! (compile "go build"))
:desc "go clean" "c" (λ! (compile "go clean")))
(:prefix ("t" . "test")
"t" #'+go/test-rerun
"a" #'+go/test-all
"s" #'+go/test-single
"n" #'+go/test-nested)))
(def-package! gorepl-mode
:commands (gorepl-run gorepl-run-load-current-file)
:config
(unless (executable-find "gore")
(warn "go-mode: couldn't find gore, REPL support disabled")))
:commands gorepl-run-load-current-file)
(def-package! company-go
:init (setq command-go-gocode-command "gocode")
:when (featurep! :completion company)
:when (and (featurep! :completion company)
(not (featurep! +lsp)))
:after go-mode
:config
(if (executable-find command-go-gocode-command)
(set! :company-backend 'go-mode '(company-go))
(warn "go-mode: couldn't find gocode, code completion won't work")))
(set-company-backend! 'go-mode 'company-go)
(setq company-go-show-annotation t))

13
modules/lang/go/doctor.el Normal file
View file

@ -0,0 +1,13 @@
;; -*- lexical-binding: t; no-byte-compile: t; -*-
;;; lang/go/doctor.el
(unless (executable-find "guru")
(warn! "Couldn't find guru. Refactoring commands (go-guru-*) won't work"))
(unless (executable-find "gore")
(warn! "Couldn't find gore. REPL will not work"))
(when (featurep! :completion company)
(require 'company-go)
(unless (executable-find company-go-gocode-command)
(warn! "Couldn't find gocode. Code completion won't work")))

View file

@ -2,14 +2,39 @@
;;;###if (featurep! +dante)
(def-package! dante
:after haskell-mode
:hook (haskell-mode . dante-mode)
:hook (haskell-mode-local-vars . dante-mode)
:init
(setq dante-load-flags '(;; defaults:
"+c"
"-Wwarn=missing-home-modules"
"-fno-diagnostics-show-caret"
;; neccessary to make attrap-attrap useful:
"-Wall"
;; necessary to make company completion useful:
"-fdefer-typed-holes"
"-fdefer-type-errors"))
:config
(add-hook 'haskell-mode-hook #'interactive-haskell-mode)
(when (featurep! :tools flycheck)
(flycheck-add-next-checker 'haskell-dante '(warning . haskell-hlint)))
(unless (executable-find "cabal")
(warn "haskell-mode: couldn't find cabal")
(remove-hook 'haskell-mode-hook #'dante-mode))
(set-company-backend! 'dante-mode #'dante-company)
(add-hook 'dante-mode-hook #'flycheck-mode))
(defun +haskell*restore-modified-state (orig-fn &rest args)
"Dante quietly saves the current buffer (without triggering save hooks) before
invoking flycheck, unexpectedly leaving the buffer in an unmodified state. This
is annoying if we depend on save hooks to do work on the buffer (like
reformatting), so we restore a (false) modified state."
(let ((modified-p (buffer-modified-p)))
(apply orig-fn args)
(if modified-p (set-buffer-modified-p t))))
(advice-add #'dante-async-load-current-buffer :around #'+haskell*restore-modified-state)
(when (featurep 'evil)
(add-hook 'dante-mode-hook #'evil-normalize-keymaps))
(map! :map dante-mode-map
:localleader
"t" #'dante-type-at
"i" #'dante-info
"l" #'haskell-process-load-or-reload
"e" #'dante-eval-block
"a" #'attrap-attrap))

View file

@ -2,17 +2,29 @@
;;;###if (featurep! +intero)
(def-package! intero
:hook (haskell-mode . intero-mode)
:commands intero-mode
:init
(defun +haskell|init-intero ()
"Initializes `intero-mode' in haskell-mode, unless stack isn't installed.
This is necessary because `intero-mode' doesn't do its own error checks."
(when (derived-mode-p 'haskell-mode)
(if (executable-find "stack")
(intero-mode +1)
(message "Couldn't find stack. Refusing to enable intero-mode."))))
(add-hook 'haskell-mode-local-vars-hook #'+haskell|init-intero)
:config
(unless (executable-find "stack")
(warn "haskell-mode: couldn't find stack, disabling intero")
(remove-hook 'haskell-mode-hook #'intero-mode))
(setq haskell-compile-cabal-build-command "stack build --fast")
(set-lookup-handlers! 'intero-mode :definition #'intero-goto-definition)
(set-company-backend! 'intero-mode 'intero-company)
(when (featurep! :tools flycheck)
(flycheck-add-next-checker 'intero '(warning . haskell-hlint)))
(add-hook! 'intero-mode-hook #'(flycheck-mode eldoc-mode))
(set! :popup "^intero:backend:" :regex t :size 12)
(set! :jump 'haskell-mode :definition #'intero-goto-definition))
(def-package! hindent
:hook (haskell-mode . hindent-mode))
(when (featurep 'evil)
(add-hook 'intero-mode-hook #'evil-normalize-keymaps))
(map! :localleader
:map intero-mode-map
"t" #'intero-type-at
"i" #'intero-info
"l" #'intero-repl-load
"e" #'intero-repl-eval-region
"a" #'intero-apply-suggestions))

View file

@ -0,0 +1,10 @@
;;; lang/haskell/+lsp.el -*- lexical-binding: t; -*-
(def-package! lsp-haskell
:after haskell-mode
:init (add-hook 'haskell-mode-hook #'lsp!)
:config
(when IS-MAC
(setq lsp-haskell-process-path-hie "hie-wrapper"))
;; Does some strange indentation if it pastes in the snippet
(setq-hook! 'haskell-mode-hook yas-indent-line 'fixed))

View file

@ -1,6 +1,25 @@
#+TITLE: :lang haskell
#+TITLE: lang/haskell
#+DATE: January 16, 2017
#+SINCE: v0.7
#+STARTUP: inlineimages
This module adds [[https://www.haskell.org/][Haskell]] support, powered by either [[https://haskell-lang.org/intero][intero]] (the default) or [[https://github.com/jyp/dante][dante]].
* Table of Contents :TOC:
- [[#description][Description]]
- [[#external-resources][External resources]]
- [[#module-flags][Module Flags]]
- [[#plugins][Plugins]]
- [[#prerequisites][Prerequisites]]
- [[#stack][Stack]]
- [[#cabal][Cabal]]
- [[#lsp][LSP]]
- [[#haskell-packages][Haskell packages]]
- [[#configuration][Configuration]]
- [[#using-the-new-style-cabal-repl][Using the new-style cabal REPL]]
- [[#troubleshooting][Troubleshooting]]
* Description
This module adds [[https://www.haskell.org/][Haskell]] support, powered by either [[https://haskell-lang.org/intero][intero]] (the default), [[https://github.com/jyp/dante][dante]]
or [[https://github.com/emacs-lsp/lsp-haskell][LSP]].
+ Code completion (~company-ghc~)
+ Look up documentation (~hoogle~)
@ -10,102 +29,130 @@ This module adds [[https://www.haskell.org/][Haskell]] support, powered by eithe
+ Code navigation (~dante~)
+ [[https://github.com/hlissner/emacs-snippets/tree/master/haskell-mode][Snippets]]
#+begin_quote
Haskell contends with C and Ruby as my favorite language. My Haskell code will never save the world, but I'll reach for it for small projects and programming exercises (like projecteuler.com or exercism.io).
I'd love to incorporate it into my machine learning work, but Python and Julia hold that crown. For now.
#+end_quote
* Table of Contents :TOC:
- [[#install][Install]]
- [[#intero][Intero]]
- [[#dante][Dante]]
- [[#troubleshooting][Troubleshooting]]
- [[#resources][Resources]]
* Install
This module has two submodules: *Intero* or *Dante*. To activate one, specify one or the other in your pubilc ~init.el~, e.g.:
#+BEGIN_SRC emacs-lisp
(doom! :lang (haskell +intero))
;; or
(doom! :lang (haskell +dante))
#+END_SRC
Your dependencies will change slightly, depending on which you choose:
** Intero
*** Haskell
To get started you must install *stack*:
**** MacOS
#+BEGIN_SRC sh :tangle (if (doom-system-os 'macos) "yes")
brew install haskell-stack
stack setup
#+END_SRC
**** Arch Linux
#+BEGIN_SRC sh :dir /sudo:: :tangle (if (doom-system-os 'arch) "yes")
sudo pacman --needed --noconfirm -S stack
# Replace pacaur with your AUR package manager of choice
pacaur --needed --noconfirm -S ncurses5-compat-lib
stack setup
#+END_SRC
*** External dependencies
This module requires ~ghc-mod~.
#+BEGIN_SRC sh
stack install ghc-mod
#+END_SRC
Also ensure that ~\~/.local/bin~ is in ~PATH~:
#+BEGIN_SRC sh
# place this in your profile file, like ~/.bash_profile or ~/.zshenv
export PATH="~/.local/bin:$PATH"
#+END_SRC
** Dante
*** Haskell
To get started with Dante and Haskell, you must install cabal
+ cabal (the haskell package builder)
+ ghc/ghci (the compiler, syntax checker & repl)
**** MacOS
#+BEGIN_SRC sh
brew install cabal-install ghc
#+END_SRC
**** Arch Linux
#+BEGIN_SRC sh
sudo pacman --needed --noconfirm -S cabal-install ghc
#+END_SRC
*** External dependencies
Dante requires ~ghc-mod~ and ~hoogle~:
#+BEGIN_SRC sh
cabal update
cabal install happy haskell-src-exts # ghc-mod/hoogle dependencies
cabal ghc-mod hoogle
#+END_SRC
And add Cabal's bin path to $PATH:
#+BEGIN_SRC sh
export PATH="$HOME/.cabal/bin:$PATH"
#+END_SRC
* Troubleshooting
+ Stack users: a ~dist/setup-config~ in your project may cause [[ https://github.com/DanielG/ghc-mod/wiki#known-issues-related-to-stack][ghc-mod to not
work]].
* Resources
** External resources
Here are a few resources I've found indespensible in my Haskell adventures:
+ [[http://learnyouahaskell.com/][Learn you a haskell for great good]]
+ [[http://haskellbook.com/][Haskell Programming from first principles]]
+ [[https://github.com/krispo/awesome-haskell][Awesome Haskell]]: an extensive list of haskell resources
+ [[https://docs.haskellstack.org/en/stable/README/][The Haskell Tool Stack docs]]
** Module Flags
+ =+intero= Enables intero; a comprehensive, stack-based development environment
for Haskell.
+ =+dante= Enables dante; a fork of intero aimed at lightweightedness. It
doesn't depend on =stack=, supports both ~cabal~-only and ~stack~ projects,
but lacks eldoc support.
+ =+lsp= Enables lsp-haskell (this requires the ~:tools lsp~ to be enabled).
** Plugins
+ [[https://github.com/haskell/haskell-mode][haskell-mode]]
+ =+dante=
+ [[https://github.com/jyp/dante][dante]]
+ [[https://github.com/jyp/attrap][attrap]]
+ =+intero=
+ [[https://github.com/chrisdone/intero][intero]]
+ =+lsp=
+ [[https://github.com/emacs-lsp/lsp-haskell][lsp-haskell]]
* Prerequisites
Depending on whether you use Intero, Dante or LSP, your dependencies will
differ:
+ Intero and LSP users need =stack=
+ Dante users need =cabal=, =ghc= and =ghc-mod=
+ LSP users need the =haskell-ide-engine= LSP server
+ All users will need the =hoogle= package
** Stack
To use Intero, you need =stack=:
*** MacOS
#+BEGIN_SRC sh
brew install haskell-stack
stack setup
#+END_SRC
*** Arch Linux
#+BEGIN_SRC sh
sudo pacman -S stack
# Replace pacaur with your AUR package manager of choice
pacaur -S ncurses5-compat-lib
stack setup
#+END_SRC
** Cabal
To use Dante, you need =cabal= (the haskell package builder) and =ghci= (the
compiler, syntax checker & repl):
*** MacOS
#+BEGIN_SRC sh
brew install cabal-install ghc
#+END_SRC
*** Arch Linux
#+BEGIN_SRC sh
sudo pacman -S cabal-install ghc
#+END_SRC
** LSP
You will need =stack= and =git= installed.
You will find a comprehensive [[https://github.com/haskell/haskell-ide-engine#installation][install guide for haskell-ide-engine on its
project page]], but here's a TL;DR:
*** MacOS
haskell-ide-engine must be build and installed manually on MacOS, e.g.
#+BEGIN_SRC emacs-lisp
git clone https://github.com/haskell/haskell-ide-engine
cd haskell-ide-engine
make
#+END_SRC
*** Arch Linux
=haskell-ide-engine-git= is available on the AUR
#+BEGIN_SRC emacs-lisp
yay -S haskell-ide-engine-git
#+END_SRC
** Haskell packages
You'll need to install the following packages using ~stack~ or ~cabal~:
+ (Dante users) =ghc-mod=
#+BEGIN_SRC sh
stack install ghc-mod
# or
cabal install ghc-mod
#+END_SRC
+ =hoogle=
#+BEGIN_SRC sh
cabal update
cabal install happy haskell-src-exts # ghc-mod/hoogle dependencies
cabal ghc-mod hoogle
# or
stack install ghc-mod
stack install hoogle
#+END_SRC
And ensure the binaries for these packages are in your ~PATH~, e.g.
#+BEGIN_SRC sh
# place this in your profile file, like ~/.bash_profile or ~/.zshenv
export PATH="~/.local/bin:$PATH"
#+END_SRC
* Configuration
** Using the new-style cabal REPL
=haskell-mode= will typically detect what REPL to run based on your project
(e.g. stack, (old-style) cabal or ghc). If you want the new-style cabal REPL you
must set ~haskell-process-type~ manually:
#+BEGIN_SRC emacs-lisp
(setq haskell-process-type 'cabal-new-repl)
#+END_SRC
* Troubleshooting
+ Stack users: a ~dist/setup-config~ file in your project may cause [[https://github.com/DanielG/ghc-mod/wiki#known-issues-related-to-stack][ghc-mod to
not work]].

View file

@ -0,0 +1,14 @@
;;; lang/haskell/autoload.el -*- lexical-binding: t; -*-
;;;###autoload
(defun +haskell/open-repl (&optional arg)
"Opens a Haskell REPL."
(interactive "P")
(if-let*
((window
(display-buffer
(if (featurep! +intero)
(intero-repl-buffer arg)
(haskell-session-interactive-buffer (haskell-session))))))
(window-buffer window)
(error "Failed to display Haskell REPL")))

View file

@ -1,40 +1,32 @@
;;; lang/haskell/config.el -*- lexical-binding: t; -*-
(cond ((featurep! +intero) (load! +intero))
((featurep! +dante) (load! +dante)))
(cond ((featurep! +intero) (load! "+intero"))
((featurep! +dante) (load! "+dante"))
((featurep! +lsp) (load! "+lsp")))
;;
;; Common plugins
;;
;; Common packages
(def-package! haskell-mode
:mode "\\.hs$"
:mode ("\\.ghci$" . ghci-script-mode)
:mode ("\\.cabal$" . haskell-cabal-mode)
:interpreter (("runghc" . haskell-mode)
("runhaskell" . haskell-mode))
:config
(load "haskell-mode-autoloads" nil t)
(after! haskell-mode
(setq haskell-process-suggest-remove-import-lines t ; warnings for redundant imports etc
haskell-process-auto-import-loaded-modules t
haskell-process-show-overlays (not (featurep! :tools flycheck))) ; redundant with flycheck
(set! :repl 'haskell-mode #'switch-to-haskell)
(push ".hi" completion-ignored-extensions)
(set-lookup-handlers! 'haskell-mode :definition #'haskell-mode-jump-to-def-or-tag)
(set-file-template! 'haskell-mode :trigger #'haskell-auto-insert-module-template :project t)
(set-repl-handler! '(haskell-mode haskell-cabal-mode literate-haskell-mode) #'+haskell/open-repl)
(autoload 'switch-to-haskell "inf-haskell" nil t)
(after! inf-haskell
(map! :map inferior-haskell-mode-map "ESC ESC" #'doom/popup-close)))
(add-hook! 'haskell-mode-hook
#'(haskell-collapse-mode ; support folding haskell code blocks
interactive-haskell-mode))
(add-to-list 'completion-ignored-extensions ".hi")
(def-package! company-ghc
:when (featurep! :completion company)
:after haskell-mode
:init
(add-hook 'haskell-mode-hook #'ghc-comp-init)
:config
(if (executable-find "ghc-mod")
(set! :company-backend 'haskell-mode #'company-ghc)
(warn "haskell-mode: couldn't find ghc-mode")
(remove-hook 'haskell-mode-hook #'ghc-comp-init))
(setq company-ghc-show-info 'oneline))
(map! :localleader
:map haskell-mode-map
;; this is set to use cabal for dante users and stack for intero users:
"b" #'haskell-process-cabal-build
"c" #'haskell-cabal-visit-file
"h" #'haskell-hide-toggle
"H" #'haskell-hide-toggle-all))

View file

@ -0,0 +1,16 @@
;; -*- lexical-binding: t; no-byte-compile: t; -*-
;;; lang/haskell/doctor.el
(when (featurep! +dante)
(unless (executable-find "cabal")
(warn! "Couldn't find cabal, haskell-mode may have issues")))
(when (featurep! +intero)
(unless (executable-find "stack")
(warn! "Couldn't find stack. Intero will not work")))
(when (or (featurep! +dante) (featurep! +intero))
(unless (executable-find "hlint")
(warn! "Couldn't find hlint. Flycheck may have issues in haskell-mode")))

View file

@ -2,13 +2,11 @@
;;; lang/haskell/packages.el
(package! haskell-mode)
(when (featurep! :completion company)
(package! company-ghc))
;;
(cond ((featurep! +dante)
(package! dante))
(t
(package! intero)
(package! hindent)))
(package! dante)
(package! attrap))
((featurep! +intero)
(package! intero))
((featurep! +lsp)
(package! lsp-haskell)))

View file

@ -1,4 +1,8 @@
;;; lang/hy/config.el -*- lexical-binding: t; -*-
(def-package! hy-mode
:mode "\\.hy$")
:mode "\\.hy\\'"
:interpreter "hy"
:config
(set-repl-handler! 'hy-mode #'hy-shell-start-or-switch-to-shell)
(set-company-backend! 'hy-mode 'company-hy))

View file

@ -1,3 +1,4 @@
;;; lang/hy/packages.el -*- no-byte-compile: t; -*-
;; -*- no-byte-compile: t; -*-
;;; lang/hy/packages.el
(package! hy-mode)

View file

@ -0,0 +1,3 @@
#+TITLE: :lang idris
Adds support for the [[https://www.idris-lang.org/][idris]] programming language.

View file

@ -0,0 +1,19 @@
;;; lang/idris/config.el -*- lexical-binding: t; -*-
(after! idris-mode
(add-hook! 'idris-mode-hook 'turn-on-idris-simple-indent)
(set-repl-handler! 'idris-mode 'idris-pop-to-repl)
(set-lookup-handlers! 'idris-mode
:documentation #'idris-docs-at-point
:file #'idris-load-file)
(map! :localleader
:map idris-mode-map
"r" #'idris-load-file
"t" #'idris-type-at-point
"d" #'idris-add-clause
"l" #'idris-make-lemma
"c" #'idris-case-split
"w" #'idris-make-with-block
"m" #'idris-add-missing
"p" #'idris-proof-search
"h" #'idris-docs-at-point))

View file

@ -0,0 +1,4 @@
;; -*- no-byte-compile: t; -*-
;;; lang/idris/packages.el
(package! idris-mode)

View file

@ -6,7 +6,7 @@
(def-package! eclim
:hook (java-mode . eclim-mode)
:config
(set! :jump 'java-mode
(set-lookup-handlers! 'java-mode
:definition #'eclim-java-find-declaration
:references #'eclim-java-find-references
:documentation #'eclim-java-show-documentation-for-current-element)
@ -16,43 +16,35 @@
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
"r" #'+java/refactor-menu
"c" #'+java/compile-menu
"p" #'+java/project-menu))
(map! :localleader
:map java-mode-map
(:prefix "r"
"gc" #'eclim-java-constructor
"gg" #'eclim-java-generate-getter-and-setter
"oi" #'eclim-java-import-organize
"f" #'eclim-java-format
"r" #'eclim-java-refactor-rename-symbol-at-point)
(:prefix "h"
"." #'eclim-java-show-documentation-for-current-element
"r" #'eclim-java-find-references
"c" #'eclim-java-call-hierarchy
"h" #'eclim-java-hierarchy
"p" #'eclim-problems
"r" #'meghanada-reference
"t" #'meghanada-typeinfo)
(:prefix "b"
"b" #'eclim-project-build
"c" #'eclim-project-create
"d" #'eclim-project-delete
"g" #'eclim-project-goto
"i" #'eclim-project-import
"k" #'eclim-project-close
"o" #'eclim-project-open
"u" #'eclim-project-update)))
(def-package! company-emacs-eclim
:when (featurep! :completion company)
:after java-mode
:config
(set! :company-backend 'java-mode '(company-emacs-eclim)))
(set-company-backend! 'java-mode '(company-emacs-eclim)))

10
modules/lang/java/+lsp.el Normal file
View file

@ -0,0 +1,10 @@
;;; lang/java/+lsp.el -*- lexical-binding: t; -*-
;;;###if (featurep! +lsp)
(def-package! lsp-java
:after-call java-mode
:init (add-hook 'java-mode-hook #'lsp!)
:config
;; TODO keybinds
;; TODO treemacs integration (?)
)

View file

@ -3,39 +3,27 @@
(def-package! meghanada
:hook (java-mode . meghanada-mode)
:config
:init
(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-flycheck (featurep! :tools flycheck)
meghanada-use-eldoc t
meghanada-use-auto-start t)
(set! :jump 'java-mode
:config
(set-lookup-handlers! 'java-mode
:definition #'meghanada-jump-declaration
:references #'meghanada-reference)
(add-hook! 'meghanada-mode-hook #'(flycheck-mode eldoc-mode))
;;
(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))
(map! :localleader
:map java-mode-map
(:prefix "r"
"ia" #'meghanada-import-all
"io" #'meghanada-optimize-import
"l" #'meghanada-local-variable
"f" #'meghanada-code-beautify)
(:prefix "h"
"r" #'meghanada-reference
"t" #'meghanada-typeinfo)
(:prefix "b"
"f" #'meghanada-compile-file
"p" #'meghanada-compile-project)))

View file

@ -24,9 +24,48 @@
;;;###autoload
(defun +java|android-mode-maybe ()
(when (doom-project-has! (or "local.properties"
"AndroidManifest.xml"
"src/main/AndroidManifest.xml"))
(when (project-file-exists-p! (or "local.properties"
"AndroidManifest.xml"
"src/main/AndroidManifest.xml"))
(android-mode +1)
(doom/set-build-command "./gradlew %s" "build.gradle")))
;;;###autoload
(defun +java-current-package ()
"Converts the current file's path into a namespace.
For example: ~/some/project/src/net/lissner/game/MyClass.java
Is converted to: net.lissner.game
It does this by ignoring everything before the nearest package root (see
`+java-project-package-roots' to control what this function considers a package
root)."
(unless (eq major-mode 'java-mode)
(user-error "Not in a java-mode buffer"))
(let* ((project-root (file-truename (doom-project-root)))
(file-path (file-name-sans-extension
(file-truename (or buffer-file-name
default-directory))))
(src-root (cl-loop for root in +java-project-package-roots
if (and (stringp root)
(locate-dominating-file file-path root))
return (file-name-directory (file-relative-name file-path (expand-file-name root it)))
if (and (integerp root)
(> root 0)
(let* ((parts (split-string (file-relative-name file-path project-root) "/"))
(fixed-parts (reverse (nbutlast (reverse parts) root))))
(when fixed-parts
(string-join fixed-parts "/"))))
return it)))
(when src-root
(string-remove-suffix "." (replace-regexp-in-string "/" "." src-root)))))
;;;###autoload
(defun +java-current-class ()
"Get the class name for the current file."
(unless (eq major-mode 'java-mode)
(user-error "Not in a java-mode buffer"))
(unless buffer-file-name
(user-error "This buffer has no filepath; cannot guess its class name"))
(or (file-name-sans-extension (file-name-base (buffer-file-name)))
"ClassName"))

View file

@ -1,28 +1,45 @@
;;; lang/java/config.el -*- lexical-binding: t; -*-
(defvar +java-project-package-roots (list "java/" "test/" "main/" "src/" 1)
"A list of relative directories (strings) or depths (integer) used by
`+java-current-package' to delimit the namespace from the current buffer's full
file path. Each root is tried in sequence until one is found.
If a directory is encountered in the file path, everything before it (including
it) will be ignored when converting the path into a namespace.
An integer depth is how many directories to pop off the start of the relative
file path (relative to the project root). e.g.
Say the absolute path is ~/some/project/src/java/net/lissner/game/MyClass.java
The project root is ~/some/project
If the depth is 1, the first directory in src/java/net/lissner/game/MyClass.java
is removed: java.net.lissner.game.
If the depth is 2, the first two directories are removed: net.lissner.game.")
;;
;; java-mode
(add-hook 'java-mode-hook #'rainbow-delimiters-mode)
(cond ((featurep! +meghanada) (load! +meghanada))
((featurep! +eclim) ; FIXME lang/java +eclim
;;(load! +eclim)
(warn "java-mode: eclim support isn't implemented yet")))
(cond ((featurep! +lsp) (load! "+lsp"))
((featurep! +meghanada) (load! "+meghanada")))
;;
;; Common plugins
;;
;; Common packages
(def-package! android-mode
:commands android-mode
:init
(add-hook! (java-mode groovy-mode nxml-mode) #'+java|android-mode-maybe)
:config
(set! :yas-minor-mode 'android-mode)
(set! :company-dict-minor-mode 'android-mode))
(set-yas-minor-mode! 'android-mode))
(def-package! groovy-mode
:mode "\\.g\\(radle\\|roovy\\)$"
:mode "\\.g\\(?:radle\\|roovy\\)$"
:config
(set! :eval 'groovy-mode "groovy"))
(set-eval-handler! 'groovy-mode "groovy"))

View file

@ -12,3 +12,5 @@
(when (featurep! :completion company)
(package! company-emacs-eclim)))
(when (featurep! +lsp)
(package! lsp-java))

View file

@ -1,174 +0,0 @@
;;; lang/javascript/+screeps.el -*- lexical-binding: t; -*-
;; TODO Constants may be out-of-date
(defconst screeps-objects
'("ConstructionSite" "Creep" "Flag" "Game" "Memory" "Mineral" "Nuke"
"OwnedStructure" "PathFinder" "RawMemory" "Resource" "Room"
"RoomObject" "RoomPosition" "Source"
"Structure" "StructureController" "StructureExtension"
"StructureExtractor" "StructureKeeperLair" "StructureLab"
"StructureLink" "StructureNuker" "StructureObserver"
"StructurePortal" "StructurePowerBank" "StructurePowerSpawn"
"StructureRampart" "StructureRoad" "StructureSpawn"
"StructureStorage" "StructureTerminal" "StructureTower"
"StructureWall"))
(defconst screeps-constants
'("OK" "ERR_NOT_OWNER" "ERR_NO_PATH" "ERR_NAME_EXISTS" "ERR_BUSY"
"ERR_NOT_FOUND" "ERR_NOT_ENOUGH_ENERGY" "ERR_NOT_ENOUGH_RESOURCES"
"ERR_INVALID_TARGET" "ERR_FULL" "ERR_NOT_IN_RANGE"
"ERR_INVALID_ARGS" "ERR_TIRED" "ERR_NO_BODYPART"
"ERR_NOT_ENOUGH_EXTENSIONS" "ERR_RCL_NOT_ENOUGH"
"ERR_GCL_NOT_ENOUGH"
"FIND_EXIT_TOP" "FIND_EXIT_RIGHT" "FIND_EXIT_BOTTOM"
"FIND_EXIT_LEFT" "FIND_EXIT" "FIND_CREEPS" "FIND_MY_CREEPS"
"FIND_HOSTILE_CREEPS" "FIND_SOURCES_ACTIVE" "FIND_SOURCES"
"FIND_DROPPED_ENERGY" "FIND_DROPPED_RESOURCES" "FIND_STRUCTURES"
"FIND_MY_STRUCTURES" "FIND_HOSTILE_STRUCTURES" "FIND_FLAGS"
"FIND_CONSTRUCTION_SITES" "FIND_MY_SPAWNS" "FIND_HOSTILE_SPAWNS"
"FIND_MY_CONSTRUCTION_SITES" "FIND_HOSTILE_CONSTRUCTION_SITES"
"FIND_MINERALS" "FIND_NUKES"
"TOP" "TOP_RIGHT" "RIGHT" "BOTTOM_RIGHT" "BOTTOM" "BOTTOM_LEFT"
"LEFT" "TOP_LEFT"
"COLOR_RED" "COLOR_PURPLE" "COLOR_BLUE" "COLOR_CYAN" "COLOR_GREEN"
"COLOR_YELLOW" "COLOR_ORANGE" "COLOR_BROWN" "COLOR_GREY"
"COLOR_WHITE"
"LOOK_CREEPS" "LOOK_ENERGY" "LOOK_RESOURCES" "LOOK_SOURCES"
"LOOK_MINERALS" "LOOK_STRUCTURES" "LOOK_FLAGS"
"LOOK_CONSTRUCTION_SITES" "LOOK_NUKES" "LOOK_TERRAIN"
"OBSTACLE_OBJECT_TYPES"
"MOVE" "WORK" "CARRY" "ATTACK" "RANGED_ATTACK" "TOUGH" "HEAL"
"CLAIM"
"BODYPART_COST"
"CREEP_LIFE_TIME" "CREEP_CLAIM_LIFE_TIME" "CREEP_CORPSE_RATE"
"CARRY_CAPACITY" "HARVEST_POWER" "HARVEST_MINERAL_POWER"
"REPAIR_POWER" "DISMANTLE_POWER" "BUILD_POWER" "ATTACK_POWER"
"UPGRADE_CONTROLLER_POWER" "RANGED_ATTACK_POWER" "HEAL_POWER"
"RANGED_HEAL_POWER" "REPAIR_COST" "DISMANTLE_COST"
"RAMPART_DECAY_AMOUNT" "RAMPART_DECAY_TIME" "RAMPART_HITS"
"RAMPART_HITS_MAX"
"ENERGY_REGEN_TIME" "ENERGY_DECAY"
"SPAWN_HITS" "SPAWN_ENERGY_START" "SPAWN_ENERGY_CAPACITY"
"CREEP_SPAWN_TIME"
"SOURCE_ENERGY_CAPACITY" "SOURCE_ENERGY_NEUTRAL_CAPACITY"
"SOURCE_ENERGY_KEEPER_CAPACITY"
"WALL_HITS" "WALL_HITS_MAX"
"EXTENSION_HITS" "EXTENSION_ENERGY_CAPACITY"
"ROAD_HITS" "ROAD_WEAROUT" "ROAD_DECAY_AMOUNT" "ROAD_DECAY_TIME"
"LINK_HITS" "LINK_HITS_MAX" "LINK_CAPACITY" "LINK_COOLDOWN"
"LINK_LOSS_RATIO"
"STORAGE_CAPACITY" "STORAGE_HITS"
"STRUCTURE_SPAWN" "STRUCTURE_EXTENSION" "STRUCTURE_ROAD"
"STRUCTURE_WALL" "STRUCTURE_RAMPART" "STRUCTURE_KEEPER_LAIR"
"STRUCTURE_PORTAL" "STRUCTURE_CONTROLLER" "STRUCTURE_LINK"
"STRUCTURE_STORAGE" "STRUCTURE_TOWER" "STRUCTURE_OBSERVER"
"STRUCTURE_POWER_BANK" "STRUCTURE_POWER_SPAWN" "STRUCTURE_EXTRACTOR"
"STRUCTURE_LAB" "STRUCTURE_TERMINAL" "STRUCTURE_CONTAINER"
"STRUCTURE_NUKER"
"CONSTRUCTION_COST"
"CONSTRUCTION_COST_ROAD_SWAMP_RATIO"
"CONTROLLER_LEVELS" "CONTROLLER_STRUCTURES" "CONTROLLER_DOWNGRADE"
"CONTROLLER_CLAIM_DOWNGRADE" "CONTROLLER_RESERVE"
"CONTROLLER_RESERVE_MAX" "CONTROLLER_MAX_UPGRADE_PER_TICK"
"CONTROLLER_ATTACK_BLOCKED_UPGRADE"
"TOWER_HITS" "TOWER_CAPACITY" "TOWER_ENERGY_COST"
"TOWER_POWER_ATTACK" "TOWER_POWER_HEAL" "TOWER_POWER_REPAIR"
"TOWER_OPTIMAL_RANGE" "TOWER_FALLOFF_RANGE" "TOWER_FALLOFF"
"OBSERVER_HITS" "OBSERVER_RANGE"
"POWER_BANK_HITS" "POWER_BANK_CAPACITY_MAX"
"POWER_BANK_CAPACITY_MIN" "POWER_BANK_CAPACITY_CRIT"
"POWER_BANK_DECAY" "POWER_BANK_HIT_BACK"
"POWER_SPAWN_HITS" "POWER_SPAWN_ENERGY_CAPACITY"
"POWER_SPAWN_POWER_CAPACITY" "POWER_SPAWN_ENERGY_RATIO"
"EXTRACTOR_HITS"
"LAB_HITS" "LAB_MINERAL_CAPACITY"
"LAB_ENERGY_CAPACITY" "LAB_BOOST_ENERGY" "LAB_BOOST_MINERAL"
"LAB_COOLDOWN"
"GCL_POW" "GCL_MULTIPLY" "GCL_NOVICE"
"MODE_SIMULATION" "MODE_SURVIVAL" "MODE_WORLD" "MODE_ARENA"
"TERRAIN_MASK_WALL" "TERRAIN_MASK_SWAMP" "TERRAIN_MASK_LAVA"
"MAX_CONSTRUCTION_SITES" "MAX_CREEP_SIZE"
"MINERAL_REGEN_TIME" "MINERAL_MIN_AMOUNT" "MINERAL_RANDOM_FACTOR"
"TERMINAL_CAPACITY" "TERMINAL_HITS" "TERMINAL_SEND_COST"
"TERMINAL_MIN_SEND"
"CONTAINER_HITS" "CONTAINER_CAPACITY" "CONTAINER_DECAY"
"CONTAINER_DECAY_TIME" "CONTAINER_DECAY_TIME_OWNED"
"NUKER_HITS" "NUKER_COOLDOWN" "NUKER_ENERGY_CAPACITY"
"NUKER_GHODIUM_CAPACITY" "NUKE_LAND_TIME" "NUKE_RANGE" "NUKE_DAMAGE"
"RESOURCE_ENERGY" "RESOURCE_POWER"
"RESOURCE_HYDROGEN" "RESOURCE_OXYGEN" "RESOURCE_UTRIUM"
"RESOURCE_LEMERGIUM" "RESOURCE_KEANIUM" "RESOURCE_ZYNTHIUM"
"RESOURCE_CATALYST" "RESOURCE_GHODIUM"
"RESOURCE_HYDROXIDE" "RESOURCE_ZYNTHIUM_KEANITE"
"RESOURCE_UTRIUM_LEMERGITE"
"RESOURCE_UTRIUM_HYDRIDE" "RESOURCE_UTRIUM_OXIDE"
"RESOURCE_KEANIUM_HYDRIDE" "RESOURCE_KEANIUM_OXIDE"
"RESOURCE_LEMERGIUM_HYDRIDE" "RESOURCE_LEMERGIUM_OXIDE"
"RESOURCE_ZYNTHIUM_HYDRIDE" "RESOURCE_ZYNTHIUM_OXIDE"
"RESOURCE_GHODIUM_HYDRIDE" "RESOURCE_GHODIUM_OXIDE"
"RESOURCE_UTRIUM_ACID" "RESOURCE_UTRIUM_ALKALIDE"
"RESOURCE_KEANIUM_ACID" "RESOURCE_KEANIUM_ALKALIDE"
"RESOURCE_LEMERGIUM_ACID" "RESOURCE_LEMERGIUM_ALKALIDE"
"RESOURCE_ZYNTHIUM_ACID" "RESOURCE_ZYNTHIUM_ALKALIDE"
"RESOURCE_GHODIUM_ACID" "RESOURCE_GHODIUM_ALKALIDE"
"RESOURCE_CATALYZED_UTRIUM_ACID"
"RESOURCE_CATALYZED_UTRIUM_ALKALIDE"
"RESOURCE_CATALYZED_KEANIUM_ACID"
"RESOURCE_CATALYZED_KEANIUM_ALKALIDE"
"RESOURCE_CATALYZED_LEMERGIUM_ACID"
"RESOURCE_CATALYZED_LEMERGIUM_ALKALIDE"
"RESOURCE_CATALYZED_ZYNTHIUM_ACID"
"RESOURCE_CATALYZED_ZYNTHIUM_ALKALIDE"
"RESOURCE_CATALYZED_GHODIUM_ACID"
"RESOURCE_CATALYZED_GHODIUM_ALKALIDE"
"REACTIONS" "BODYPARTS_ALL" "RESOURCES_ALL" "COLORS_ALL"))
(defun +javascript|init-screeps-mode ()
(when (eq major-mode 'js2-mode)
(push 'javascript-jshint flycheck-disabled-checkers)
(setq js2-additional-externs (append '("_") screeps-objects screeps-constants))))

View file

@ -2,7 +2,7 @@
This module adds Javascript support.
+ Code completion (tern)
+ Code completion (tide)
+ REPL support (nodejs-repl)
+ Refactoring commands (js2-refactor)
+ Syntax checking (flycheck)
@ -13,7 +13,6 @@ This module adds Javascript support.
* Table of Contents :TOC:
- [[#install][Install]]
- [[#node--npm][Node & NPM]]
- [[#dependencies][Dependencies]]
- [[#appendix][Appendix]]
- [[#commands][Commands]]
@ -31,16 +30,78 @@ brew install node
sudo pacman --needed --noconfirm -S nodejs npm
#+END_SRC
** Dependencies
This module optionally requires ~tern~ for code completion.
#+BEGIN_SRC sh
npm -g install tern
#+END_SRC
* Appendix
** Commands
*** JS2-mode
| command | key / ex command | description |
|----------------------------------+------------------+------------------------------------------------------------|
| ~+javascript/repl~ | =:repl= | Open the NodeJS REPL (or send the current selection to it) |
| ~+javascript/open-repl~ | =:repl= | Open the NodeJS REPL (or send the current selection to it) |
| ~+javascript/skewer-this-buffer~ | =SPC m S= | Attaches a browser to the current buffer |
*** Tide
| command | key / ex command | description |
|-------------------------+------------------+------------------------|
| ~tide-restart-server~ | =SPC m R= | Restart tide server |
| ~tide-reformat~ | =SPC m f= | Reformat region |
| ~tide-rename-symbol~ | =SPC m r s= | Rename symbol at point |
| ~tide-organize-imports~ | =SPC m r o i= | Organize imports |
*** Refactoring (js2-refactor-mode)
| command | key / ex command | description |
|---------------------------------------------------+------------------+--------------------------------------------------------------------------------------------------------------------|
| ~js2r-expand-node-at-point~ | =SPC m r e e= | Expand bracketed list according to node type at point |
| ~js2r-contract-node-at-point~ | =SPC m r c c= | Contract bracketed list according to node type at point |
| ~js2r-extract-function~ | =SPC m r e f= | Extracts the marked expressions out into a new named function. |
| ~js2r-extract-method~ | =SPC m r e m= | Extracts the marked expressions out into a new named method in an object literal. |
| ~js2r-toggle-function-expression-and-declaration~ | =SPC m r t f= | Toggle between function name() {} and var name = function (); |
| ~js2r-toggle-arrow-function-and-expression~ | =SPC m r t a= | Toggle between function expression to arrow function. |
| ~js2r-toggle-function-async~ | =SPC m r t s= | Toggle between an async and a regular function. |
| ~js2r-introduce-parameter~ | =SPC m r i p= | Changes the marked expression to a parameter in a local function. |
| ~js2r-localize-parameter~ | =SPC m r l p= | Changes a parameter to a local var in a local function. |
| ~js2r-wrap-buffer-in-iife~ | =SPC m r w i= | Wraps the entire buffer in an immediately invoked function expression |
| ~js2r-inject-global-in-iife~ | =SPC m r i g= | Creates a shortcut for a marked global by injecting it in the wrapping immediately invoked function expression |
| ~js2r-add-to-globals-annotation~ | =SPC m r a g= | Creates a /*global */ annotation if it is missing, and adds the var at point to it. |
| ~js2r-extract-var~ | =SPC m r e v= | Takes a marked expression and replaces it with a var. |
| ~js2r-extract-let~ | =SPC m r e l= | Similar to extract-var but uses a let-statement. |
| ~js2r-extract-const~ | =SPC m r e c= | Similar to extract-var but uses a const-statement. |
| ~js2r-inline-var~ | =SPC m r i v= | Replaces all instances of a variable with its initial value. |
| ~js2r-rename-var~ | =SPC m r r v= | Renames the variable on point and all occurrences in its lexical scope. |
| ~js2r-var-to-this~ | =SPC m r v t= | Changes local var a to be this.a instead. |
| ~js2r-arguments-to-object~ | =SPC m r a o= | Replaces arguments to a function call with an object literal of named arguments. |
| ~js2r-ternary-to-if~ | =SPC m r 3 i= | Converts ternary operator to if-statement. |
| ~js2r-split-var-declaration~ | =SPC m r s v= | Splits a var with multiple vars declared, into several var statements. |
| ~js2r-split-string~ | =SPC m r s s= | Splits a string. |
| ~js2r-string-to-template~ | =SPC m r s t= | Converts a string into a template string. |
| ~js2r-unwrap~ | =SPC m r u w= | Replaces the parent statement with the selected region. |
| ~js2r-log-this~ | =SPC m r l t= | Adds a console.log() statement for what is at point (or region). With a prefix argument, use JSON pretty-printing. |
| ~js2r-debug-this~ | =SPC m r d t= | Adds a debug() statement for what is at point (or region). |
| ~js2r-forward-slurp~ | =SPC m r s l= | Moves the next statement into current function, if-statement, for-loop or while-loop. |
| ~js2r-forward-barf~ | =SPC m r b a= | Moves the last child out of current function, if-statement, for-loop or while-loop. |
| ~js2r-kill~ | =SPC m r k= | Kills to the end of the line, but does not cross semantic boundaries. |
*** skewer-mode
**** general
| command | key / ex command | description |
|-------------------------------+------------------+---------------------------------------|
| ~skewer-eval-last-expression~ | =SPC m s E= | Evaluate last expression |
| ~skewer-eval-defun~ | =SPC m s e= | Evaluate function definition at point |
| ~skewer-load-buffer~ | =SPC m s f= | Load buffer into REPL |
**** css
| command | key / ex command | description |
|---------------------------------------+------------------+-------------------------------|
| ~skewer-css-eval-current-declaration~ | =SPC m s e= | Evaluate declaration at point |
| ~skewer-css-eval-current-rule~ | =SPC m s r= | Evaluate rule at point |
| ~skewer-css-eval-buffer~ | =SPC m s b= | Evaluate buffer |
| ~skewer-css-clear-all~ | =SPC m s c= | Clear all rules |
**** html
| command | key / ex command | description |
|------------------------+------------------+-----------------------|
| ~skewer-html-eval-tag~ | =SPC m s e= | Evaluate tag at point |
*** npm-mode
| command | key / ex command | description |
|---------------------------------+------------------+------------------------------------------------------------------|
| ~npm-mode-npm-init~ | =SPC m n n= | Initialize npm project |
| ~npm-mode-npm-install~ | =SPC m n i= | Install npm package |
| ~npm-mode-npm-install-save~ | =SPC m n s= | Install npm package and save to package.json |
| ~npm-mode-npm-install-save-dev~ | =SPC m n d= | Install npm package and save to package.json as a dev dependency |
| ~npm-mode-npm-uninstall~ | =SPC m n u= | Uninstall npm package |
| ~npm-mode-npm-list~ | =SPC m n l= | List npm packages |
| ~npm-mode-npm-run~ | =SPC m n r= | Run npm task |
| ~npm-mode-visit-project-file~ | =SPC m n v= | Find file in npm project |

View file

@ -11,6 +11,7 @@ ignore the cache."
(gethash project-root +javascript-npm-conf))
(let ((package-file (expand-file-name "package.json" project-root)))
(when-let* ((json (and (file-exists-p package-file)
(require 'json)
(json-read-file package-file))))
(puthash project-root json +javascript-npm-conf))))))
@ -30,16 +31,20 @@ ignore the cache."
(assq packages deps))
(t (error "Expected a package symbol or list, got %s" packages))))))
;;
;; Commands
;;;###autoload
(defun +javascript/repl ()
(defun +javascript/open-repl ()
"Open a Javascript REPL. Meaning either `skewer-repl', if any of the
skewer-*-mode's are enabled, or `nodejs-repl' otherwise."
(interactive)
(call-interactively
(if (and (featurep 'skewer-mode)
(or skewer-mode skewer-css-mode skewer-html-mode))
'skewer-repl
'nodejs-repl)))
#'skewer-repl
#'nodejs-repl)))
;;;###autoload
(defun +javascript/skewer-this-buffer ()
@ -73,3 +78,44 @@ Run this for any buffer you want to skewer."
(if skewer-css-mode (skewer-css-mode -1))
(if skewer-html-mode (skewer-html-mode -1)))))
;;
;; Hooks
;;;###autoload
(defun +javascript|add-node-modules-path ()
"Add current project's `node_modules/.bin` to `exec-path', so js tools
prioritize project-local packages over global ones."
(make-local-variable 'exec-path)
(cl-pushnew (expand-file-name "node_modules/.bin/"
(or (locate-dominating-file
(or (buffer-file-name) default-directory)
"node_modules")
(doom-project-root)))
exec-path :test #'string=))
;;;###autoload
(defun +javascript|cleanup-tide-processes ()
"Clean up dangling tsserver processes if there are no more buffers with
`tide-mode' active that belong to that server's project."
(when tide-mode
(unless (cl-loop with project-name = (tide-project-name)
for buf in (delq (current-buffer) (buffer-list))
if (and (buffer-local-value 'tide-mode buf)
(with-current-buffer buf
(string= (tide-project-name) project-name)))
return buf)
(kill-process (tide-current-server)))))
;;
;; Advice
;;;###autoload
(defun +javascript*tide-project-root ()
"Resolve to `doom-project-root' if `tide-project-root' fails."
(or tide-project-root
(or (locate-dominating-file default-directory "tsconfig.json")
(locate-dominating-file default-directory "jsconfig.json"))
(or (doom-project-root)
default-directory)))

View file

@ -1,209 +1,250 @@
;;; lang/javascript/config.el -*- lexical-binding: t; -*-
(after! (:any js2-mode rjsx-mode web-mode)
(set-docsets! '(js2-mode rjsx-mode) "JavaScript"
"AngularJS" "Backbone" "BackboneJS" "Bootstrap" "D3JS" "EmberJS" "Express"
"ExtJS" "JQuery" "JQuery_Mobile" "JQuery_UI" "KnockoutJS" "Lo-Dash"
"MarionetteJS" "MomentJS" "NodeJS" "PrototypeJS" "React" "RequireJS"
"SailsJS" "UnderscoreJS" "VueJS" "ZeptoJS")
(set-pretty-symbols! '(js2-mode rjsx-mode web-mode)
;; Functional
:def "function"
:lambda "() =>"
:composition "compose"
;; Types
:null "null"
:true "true" :false "false"
;; Flow
:not "!"
:and "&&" :or "||"
:for "for"
:return "return"
;; Other
:yield "import"))
(after! projectile
(pushnew! projectile-project-root-files "package.json")
(pushnew! projectile-globally-ignored-directories "node_modules" "flow-typed"))
;;
;; Major modes
(def-package! js2-mode
:mode "\\.js$"
:mode "\\.m?js\\'"
:interpreter "node"
:commands js2-line-break
:config
(setq js2-skip-preprocessor-directives t
js2-highlight-external-variables nil
js2-mode-show-parse-errors nil)
js-chain-indent t
;; let flycheck handle this
js2-mode-show-parse-errors nil
js2-mode-show-strict-warnings nil
;; Flycheck provides these features, so disable them: conflicting with
;; the eslint settings.
js2-strict-trailing-comma-warning nil
js2-strict-missing-semi-warning nil
;; maximum fontification
js2-highlight-level 3
js2-highlight-external-variables t)
(add-hook! 'js2-mode-hook
#'(flycheck-mode highlight-indentation-mode rainbow-delimiters-mode))
(add-hook 'js2-mode-hook #'rainbow-delimiters-mode)
;; Indent switch-case another step
(setq-hook! 'js2-mode-hook
js-switch-indent-offset js2-basic-offset
mode-name "JS2")
(set! :repl 'js2-mode #'+javascript/repl)
(set! :electric 'js2-mode :chars '(?\} ?\) ?.))
(set! :jump 'js2-mode :xref-backend #'xref-js2-xref-backend)
;; Conform switch-case indentation to js2 normal indent
(defvaralias 'js-switch-indent-offset 'js2-basic-offset)
(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)
(set-electric! 'js2-mode :chars '(?\} ?\) ?. ?:))
(set-repl-handler! 'js2-mode #'+javascript/open-repl)
(map! :map js2-mode-map
:localleader
"r" #'+javascript/refactor-menu
"S" #'+javascript/skewer-this-buffer))
;; A find-{definition,references} backend for js2-mode. NOTE The xref API is
;; unstable and may break with an Emacs update.
(def-package! xref-js2 :commands xref-js2-xref-backend)
(def-package! nodejs-repl :commands nodejs-repl)
(def-package! js2-refactor
:commands
(js2r-extract-function js2r-extract-method js2r-introduce-parameter
js2r-localize-parameter js2r-expand-object js2r-contract-object
js2r-expand-function js2r-contract-function js2r-expand-array
js2r-contract-array js2r-wrap-buffer-in-iife js2r-inject-global-in-iife
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)
: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
:hook (js2-mode . tern-mode)
:config
(advice-add #'tern-project-dir :override #'doom-project-root))
(def-package! company-tern
:when (featurep! :completion company)
:after tern
:config
(set! :company-backend 'js2-mode '(company-tern)))
(def-package! rjsx-mode
:commands rjsx-mode
:mode "\\.jsx$"
:mode "components/.+\\.js$"
:init
(defun +javascript-jsx-file-p ()
"Detect React or preact imports early in the file."
(and buffer-file-name
(equal (file-name-extension buffer-file-name) "js")
(re-search-forward "\\(^\\s-*import React\\|\\( from \\|require(\\)[\"']react\\)"
(string= (file-name-extension buffer-file-name) "js")
(re-search-forward "\\(^\\s-*import +React\\|\\( from \\|require(\\)[\"']p?react\\)"
magic-mode-regexp-match-limit t)
(progn (goto-char (match-beginning 1))
(not (sp-point-in-string-or-comment)))))
(push (cons #'+javascript-jsx-file-p 'rjsx-mode) magic-mode-alist)
(add-to-list 'magic-mode-alist '(+javascript-jsx-file-p . rjsx-mode))
:config
(set! :electric 'rjsx-mode :chars '(?\} ?\) ?. ?>))
(set-electric! 'rjsx-mode :chars '(?\} ?\) ?. ?>))
(when (featurep! :tools flycheck)
(add-hook! 'rjsx-mode-hook
;; jshint doesn't know how to deal with jsx
(push 'javascript-jshint flycheck-disabled-checkers)))
;; disable electric keys (I use snippets and `emmet-mode' instead)
(map! :map rjsx-mode-map
"<" nil
"C-d" nil)
(add-hook! rjsx-mode
;; jshint doesn't really know how to deal with jsx
(push 'javascript-jshint flycheck-disabled-checkers)))
;; `rjsx-electric-gt' relies on js2's parser to tell it when the cursor is in
;; a self-closing tag, so that it can insert a matching ending tag at point.
;; However, the parser doesn't run immediately, so a fast typist can outrun
;; it, causing tags to stay unclosed, so we force it to parse.
(defun +javascript|reparse (n)
;; if n != 1, rjsx-electric-gt calls rjsx-maybe-reparse itself
(if (= n 1) (rjsx-maybe-reparse)))
(advice-add #'rjsx-electric-gt :before #'+javascript|reparse))
(def-package! coffee-mode
:mode "\\.coffee$"
:init (setq coffee-indent-like-python-mode t))
(after! typescript-mode
(add-hook 'typescript-mode-hook #'rainbow-delimiters-mode)
(setq-hook! 'typescript-mode-hook
comment-line-break-function #'js2-line-break)
(set-electric! 'typescript-mode
:chars '(?\} ?\)) :words '("||" "&&"))
(set-docsets! 'typescript-mode "TypeScript" "AngularTS")
(set-pretty-symbols! 'typescript-mode
;; Functional
:def "function"
:lambda "() =>"
:composition "compose"
;; Types
:null "null"
:true "true" :false "false"
:int "number"
:str "string"
:bool "boolean"
;; Flow
:not "!"
:and "&&" :or "||"
:for "for"
:return "return" :yield "import"))
(def-package! web-beautify
:commands web-beautify-js
:init
(map! :map* (json-mode js2-mode-map) :n "gQ" #'web-beautify-js))
(def-package! eslintd-fix
:commands (eslintd-fix-mode eslintd-fix))
;;
;; Skewer-mode
;;
(def-package! skewer-mode
:commands (skewer-mode run-skewer)
:config
(map! :map skewer-mode-map
:localleader
:n "sE" #'skewer-eval-last-expression
:n "se" #'skewer-eval-defun
:n "sf" #'skewer-load-buffer))
(def-package! skewer-css ; in skewer-mode
:commands skewer-css-mode
:config
(map! :map skewer-css-mode-map
:localleader
:n "se" #'skewer-css-eval-current-declaration
:n "sr" #'skewer-css-eval-current-rule
:n "sb" #'skewer-css-eval-buffer
:n "sc" #'skewer-css-clear-all))
(def-package! skewer-html ; in skewer-mode
:commands skewer-html-mode
:config
(map! :map skewer-html-mode-map
:localleader
:n "se" #'skewer-html-eval-tag))
;;
;; Projects
;;
(def-project-mode! +javascript-screeps-mode
:match "/screeps\\(-ai\\)?/.+$"
:modes (+javascript-npm-mode)
: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"
:on-enter
(when (make-local-variable 'exec-path)
(push (doom-project-expand "node_modules/.bin")
exec-path)))
;; `coffee-mode'
(setq coffee-indent-like-python-mode t)
(after! coffee-mode
(set-docsets! 'coffee-mode "CoffeeScript"))
;;
;; Tools
(when (featurep! +lsp)
(add-hook! (js2-mode rjsx-mode typescript-mode) #'lsp!))
(def-package! tide
:unless (featurep! +lsp)
:defer t
:init
;; Don't let hard errors stop the user from opening js files.
(defun +javascript|init-tide ()
"Enable `tide-mode' if node is available."
(cond ((not buffer-file-name)
(add-hook 'after-save-hook #'+javascript|init-tide nil t))
((executable-find "node")
(tide-setup))
((message "Couldn't find `node', aborting tide server"))))
(add-hook! (js2-mode typescript-mode) #'+javascript|init-tide)
(defun +javascript|init-tide-in-web-mode ()
"Enable `tide-mode' if in a *.tsx file."
(when (string= (file-name-extension (or buffer-file-name "")) "tsx")
(tide-setup)))
(add-hook 'web-mode-hook #'+javascript|init-tide-in-web-mode)
:config
(setq tide-completion-detailed t
tide-always-show-documentation t)
;; code completion
(after! company
;; tide affects the global `company-backends', undo this so doom can handle
;; it buffer-locally
(setq-default company-backends (delq 'company-tide (default-value 'company-backends))))
(set-company-backend! 'tide-mode 'company-tide)
;; navigation
(set-lookup-handlers! 'tide-mode :async t
:definition #'tide-jump-to-definition
:references #'tide-references)
;; resolve to `doom-project-root' if `tide-project-root' fails
(advice-add #'tide-project-root :override #'+javascript*tide-project-root)
;; cleanup tsserver when no tide buffers are left
(add-hook! 'tide-mode-hook
(add-hook 'kill-buffer-hook #'+javascript|cleanup-tide-processes nil t))
(define-key tide-mode-map [remap +lookup/documentation] #'tide-documentation-at-point)
(map! :localleader
:map tide-mode-map
"R" #'tide-restart-server
"f" #'tide-format
"rs" #'tide-rename-symbol
"roi" #'tide-organize-imports))
(def-package! xref-js2
:when (featurep! :feature lookup)
:after (:or js2-mode rjsx-mode)
:config
(set-lookup-handlers! '(js2-mode rjsx-mode)
:xref-backend #'xref-js2-xref-backend))
(def-package! js2-refactor
:hook ((js2-mode rjsx-mode) . js2-refactor-mode)
:config
(when (featurep! :feature evil +everywhere)
(let ((js2-refactor-mode-map (evil-get-auxiliary-keymap js2-refactor-mode-map 'normal t t)))
(js2r-add-keybindings-with-prefix (format "%s r" doom-localleader-key)))))
(def-package! eslintd-fix
:commands eslintd-fix
:config
(defun +javascript|set-flycheck-executable-to-eslint ()
(setq flycheck-javascript-eslint-executable eslintd-fix-executable))
(add-hook 'eslintd-fix-mode-hook #'+javascript|set-flycheck-executable-to-eslint))
;; `skewer-mode'
(map! :localleader
:prefix "s"
(:after skewer-mode
:map skewer-mode-map
"E" #'skewer-eval-last-expression
"e" #'skewer-eval-defun
"f" #'skewer-load-buffer)
(:after skewer-css
:map skewer-css-mode-map
"e" #'skewer-css-eval-current-declaration
"r" #'skewer-css-eval-current-rule
"b" #'skewer-css-eval-buffer
"c" #'skewer-css-clear-all)
(:after skewer-html
:map skewer-html-mode-map
"e" #'skewer-html-eval-tag))
;; `npm-mode'
(map! :after npm-mode
:localleader
:map npm-mode-keymap
:prefix "n"
"n" #'npm-mode-npm-init
"i" #'npm-mode-npm-install
"s" #'npm-mode-npm-install-save
"d" #'npm-mode-npm-install-save-dev
"u" #'npm-mode-npm-uninstall
"l" #'npm-mode-npm-list
"r" #'npm-mode-npm-run
"v" #'npm-mode-visit-project-file)
;;
;; Projects
(def-project-mode! +javascript-eslintd-fix-mode
:add-hooks (eslintd-fix-mode))
(def-project-mode! +javascript-npm-mode
:modes (html-mode css-mode web-mode typescript-mode js2-mode rjsx-mode json-mode markdown-mode)
:when (locate-dominating-file default-directory "package.json")
:add-hooks (+javascript|add-node-modules-path npm-mode))
(def-project-mode! +javascript-gulp-mode
:when (locate-dominating-file default-directory "gulpfile.js"))

View file

@ -1,21 +1,21 @@
;; -*- no-byte-compile: t; -*-
;;; lang/javascript/packages.el
;; requires node npm tern js-beautify eslint eslint-plugin-react
;; major modes
(package! coffee-mode)
(package! js2-mode)
(package! js2-refactor)
(package! rjsx-mode)
(package! nodejs-repl)
(package! tern)
(package! web-beautify)
(package! skewer-mode)
(package! typescript-mode)
;; tools
(package! eslintd-fix)
(package! js2-refactor)
(package! nodejs-repl)
(package! npm-mode)
(package! skewer-mode)
(when (featurep! :completion company)
(package! company-tern))
(when (featurep! :feature jump)
(when (featurep! :feature lookup)
(package! xref-js2))
(unless (featurep! +lsp)
(package! tide))

View file

@ -9,6 +9,5 @@
(apply #'make-comint-in-buffer "Julia" "*Julia*" julia-program julia-arguments))
(pop-to-buffer buffer)
(with-current-buffer buffer
(inferior-julia-mode))))
(inferior-julia-mode))
buffer))

View file

@ -1,31 +1,30 @@
;;; lang/julia/config.el -*- lexical-binding: t; -*-
(use-package julia-mode
:mode "\\.jl$"
:interpreter "julia"
:config
(set! :repl 'julia-mode #'+julia/repl)
(set-repl-handler! 'julia-mode #'+julia/repl)
;; Borrow matlab.el's fontification of math operators
;; From <https://ogbe.net/emacsconfig.html>
(font-lock-add-keywords
'julia-mode
`((,(let ((OR "\\|"))
(concat "\\(" ;; stolen `matlab.el' operators first
"[<>!]=?" OR
"\\.[/*^']" OR
"==" OR
"=>" OR
"\\<xor\\>" OR
"[-+*\\/^&|$]=?" OR ;; this has to come before next (updating operators)
"[-!^&|*+\\/~:]" OR
;; more extra julia operators follow
"[%$]" OR
;; bitwise operators
">>>" OR ">>" OR "<<" OR
">>>=" OR ">>" OR "<<" OR
;; comparison
"[<>!]=?" OR
"\\)"))
1 font-lock-type-face))))
(dolist (mode '(julia-mode ess-julia-mode))
(font-lock-add-keywords
mode
`((,(let ((OR "\\|"))
(concat "\\(" ;; stolen `matlab.el' operators first
"[<>!]=?" OR
"\\.[/*^']" OR
"==" OR
"=>" OR
"\\<xor\\>" OR
"[-+*\\/^&|$]=?" OR ;; this has to come before next (updating operators)
"[-!^&|*+\\/~:]" OR
;; more extra julia operators follow
"[%$]" OR
;; bitwise operators
">>>" OR ">>" OR "<<" OR
">>>=" OR ">>" OR "<<" OR
;; comparison
"[<>!]=?" OR
"\\)"))
1 font-lock-type-face)))))

View file

@ -0,0 +1,15 @@
;;; lang/kotlin/autoload.el -*- lexical-binding: t; -*-
;;;autoload
(defun +kotlin-locate-gradlew-file ()
"Gradlew file location for this project."
(locate-dominating-file buffer-file-name "gradlew"))
;;;###autoload
(defun +kotlin/run-gradlew (command)
"Run gradlew in this project."
(interactive "sCommand: ")
(let ((default-directory (+kotlin-locate-gradlew-file))
(compilation-read-command nil)
(compile-command (format "sh gradlew %s" command)))
(call-interactively #'compile)))

View file

@ -0,0 +1,16 @@
;;; lang/kotlin/config.el -*- lexical-binding: t; -*-
(after! kotlin-mode
(set-docsets! 'kotlin-mode "Kotlin")
(map! :map kotlin-mode-map
:localleader
:prefix ("b" . "build")
:desc "gradlew assemble" "a" (λ! (+kotlin/run-gradlew "assemble"))
:desc "gradlew build" "b" (λ! (+kotlin/run-gradlew "build"))
:desc "gradlew test" "t" (λ! (+kotlin/run-gradlew "test"))))
(def-package! flycheck-kotlin
:when (featurep! :tools flycheck)
:after kotlin-mode
:config (add-hook 'kotlin-mode-hook #'flycheck-kotlin-setup))

View file

@ -0,0 +1,4 @@
;;; lang/kotlin/doctor.el -*- lexical-binding: t; -*-
(unless (executable-find "ktlint")
(warn! "ktlint not found. flycheck-kotlin won't work."))

View file

@ -0,0 +1,7 @@
;; -*- no-byte-compile: t; -*-
;;; lang/kotlin/packages.el
(package! kotlin-mode)
(when (featurep! :tools flycheck)
(package! flycheck-kotlin))

View file

@ -0,0 +1,88 @@
;;; lang/latex/+fontification.el -*- lexical-binding: t; -*-
;; Fontification taken from https://tex.stackexchange.com/a/86119/81279
(setq font-latex-match-reference-keywords
'(;; biblatex
("printbibliography" "[{")
("addbibresource" "[{")
;; Standard commands
("cite" "[{")
("citep" "[{")
("citet" "[{")
("Cite" "[{")
("parencite" "[{")
("Parencite" "[{")
("footcite" "[{")
("footcitetext" "[{")
;; Style-specific commands
("textcite" "[{")
("Textcite" "[{")
("smartcite" "[{")
("Smartcite" "[{")
("cite*" "[{")
("parencite*" "[{")
("supercite" "[{")
;; Qualified citation lists
("cites" "[{")
("Cites" "[{")
("parencites" "[{")
("Parencites" "[{")
("footcites" "[{")
("footcitetexts" "[{")
("smartcites" "[{")
("Smartcites" "[{")
("textcites" "[{")
("Textcites" "[{")
("supercites" "[{")
;; Style-independent commands
("autocite" "[{")
("Autocite" "[{")
("autocite*" "[{")
("Autocite*" "[{")
("autocites" "[{")
("Autocites" "[{")
;; Text commands
("citeauthor" "[{")
("Citeauthor" "[{")
("citetitle" "[{")
("citetitle*" "[{")
("citeyear" "[{")
("citedate" "[{")
("citeurl" "[{")
;; Special commands
("fullcite" "[{")
;; cleveref
("cref" "{")
("Cref" "{")
("cpageref" "{")
("Cpageref" "{")
("cpagerefrange" "{")
("Cpagerefrange" "{")
("crefrange" "{")
("Crefrange" "{")
("labelcref" "{")))
(setq font-latex-match-textual-keywords
'(;; biblatex brackets
("parentext" "{")
("brackettext" "{")
("hybridblockquote" "[{")
;; Auxiliary Commands
("textelp" "{")
("textelp*" "{")
("textins" "{")
("textins*" "{")
;; subcaption
("subcaption" "[{")))
(setq font-latex-match-variable-keywords
'(;; amsmath
("numberwithin" "{")
;; enumitem
("setlist" "[{")
("setlist*" "[{")
("newlist" "{")
("renewlist" "{")
("setlistdepth" "{")
("restartlist" "{")
("crefname" "{")))

View file

@ -0,0 +1,42 @@
;;; lang/latex/+ref.el -*- lexical-binding: t; -*-
(when (stringp +latex-bibtex-file)
(setq bibtex-completion-bibliography (list (expand-file-name +latex-bibtex-file))
reftex-default-bibliography bibtex-completion-bibliography))
(def-package! reftex
:hook (LaTeX-mode . reftex-mode)
:config
;; set up completion for citations and references
(set-company-backend! 'reftex-mode 'company-reftex-labels 'company-reftex-citations)
;; Get ReTeX working with biblatex
;; http://tex.stackexchange.com/questions/31966/setting-up-reftex-with-biblatex-citation-commands/31992#31992
(setq reftex-cite-format
'((?a . "\\autocite[]{%l}")
(?b . "\\blockcquote[]{%l}{}")
(?c . "\\cite[]{%l}")
(?f . "\\footcite[]{%l}")
(?n . "\\nocite{%l}")
(?p . "\\parencite[]{%l}")
(?s . "\\smartcite[]{%l}")
(?t . "\\textcite[]{%l}"))
reftex-plug-into-AUCTeX t
reftex-toc-split-windows-fraction 0.3)
(map! :map reftex-mode-map
:localleader
";" 'reftex-toc)
(add-hook! 'reftex-toc-mode-hook
(reftex-toc-rescan)
(map! :map 'local
:e "j" #'next-line
:e "k" #'previous-line
:e "q" #'kill-buffer-and-window
:e "ESC" #'kill-buffer-and-window)))
;; set up mode for bib files
(after! bibtex
(setq bibtex-dialect 'biblatex
bibtex-align-at-equal-sign t
bibtex-text-indentation 20)
(define-key bibtex-mode-map (kbd "C-c \\") #'bibtex-fill-entry))

View file

@ -0,0 +1,49 @@
;;; lang/latex/+viewers.el -*- lexical-binding: t; -*-
(catch 'found-viewer
(dolist (viewer +latex-viewers)
(if (pcase viewer
(`skim
(when (and IS-MAC
(file-exists-p! (or "/Applications/Skim.app"
"~/Applications/Skim.app")))
(add-to-list 'TeX-view-program-selection '(output-pdf "Skim"))))
(`sumatrapdf
(when (and IS-WINDOWS
(executable-find "SumatraPDF"))
(add-to-list 'TeX-view-program-selection '(output-pdf "SumatraPDF"))))
(`okular
(when (executable-find "okular")
;; Configure Okular as viewer. Including a bug fix
;; (https://bugs.kde.org/show_bug.cgi?id=373855)
(add-to-list 'TeX-view-program-list '("Okular" ("okular --unique file:%o" (mode-io-correlate "#src:%n%a"))))
(add-to-list 'TeX-view-program-selection '(output-pdf "Okular"))))
(`zathura
(when (executable-find "zathura")
(add-to-list 'TeX-view-program-selection '(output-pdf "Zathura"))))
(`pdf-tools
(when (featurep! :tools pdf)
(add-to-list 'TeX-view-program-selection '(output-pdf "PDF Tools"))
(when IS-MAC
;; PDF Tools isn't in `TeX-view-program-list-builtin' on macs
(add-to-list 'TeX-view-program-list '("PDF Tools" TeX-pdf-tools-sync-view)))
;; Update PDF buffers after successful LaTeX runs
(add-hook 'TeX-after-compilation-finished-function #'TeX-revert-document-buffer))))
(throw 'found-viewer t)))
;; fall back to latex-preview-pane
(add-to-list 'TeX-view-program-list '("preview-pane" latex-preview-pane-mode))
(add-to-list 'TeX-view-program-selection '(output-pdf "preview-pane")))
(after! latex-preview-pane
(setq latex-preview-pane-multifile-mode 'auctex)
(define-key! doc-view-mode-map
"ESC" #'delete-window
"q" #'delete-window
"k" (λ! (quit-window) (delete-window))))

View file

@ -0,0 +1,73 @@
#+TITLE: lang/latex
#+DATE: January 16, 2017
#+SINCE: v1.3
#+STARTUP: inlineimages
* Table of Contents :TOC_3:noexport:
- [[Description][Description]]
- [[Module Flags][Module Flags]]
- [[Plugins][Plugins]]
- [[Features][Features]]
- [[Customization][Customization]]
- [[Specifying the location of a bibtex file & corresponding PDFs][Specifying the location of a bibtex file & corresponding PDFs]]
- [[Changing the PDFs viewer][Changing the PDFs viewer]]
* Description
Provide a helping hand when working with LaTeX documents.
+ Sane defaults
+ Fontification of many popular commands
+ Pretty indentation of wrapped lines using the ~adaptive-wrap~ package
+ Spell checking with ~flycheck~
+ Change PDF viewer to Okular or ~latex-preview-pane~
+ Bibtex editor
+ Autocompletion using ~company-mode~
+ Ivy or Helm for selecting bibliography
+ Compile your .tex code only once using LatexMk
** Module Flags
+ ~+latexmk~ Use LatexMk instead of LaTeX to compile documents.
** Plugins
+ [[http://www.gnu.org/software/auctex/][auctex]]
+ [[http://elpa.gnu.org/packages/adaptive-wrap.html][adaptive-wrap]]
+ [[https://github.com/jsinglet/latex-preview-pane][latex-preview-pane]]
+ [[https://github.com/tom-tan/auctex-latexmk][auctex-latexmk]]*
+ [[https://github.com/alexeyr/company-auctex][company-auctex]]*
+ [[https://github.com/TheBB/company-reftex][company-reftex]]*
+ [[https://github.com/vspinu/company-math][company-math]]*
+ [[https://github.com/tmalsburg/helm-bibtex][ivy-bibtex]]* or [[https://github.com/tmalsburg/helm-bibtex][helm-bibtex]]*
* TODO Features
* Customization
** Specifying the location of a bibtex file & corresponding PDFs
The reftex and bibtex-completion packages have two variables that allow you to
specify where it should find your bibliography file(s) and their corresponding
PDFs:
#+BEGIN_SRC emacs-lisp
(setq reftex-default-bibliography "/your/bib/file.bib")
;; Optionally specifying a location for the corresponding PDFs
(setq bibtex-completion-library-path (list "/your/bib/pdfs"))
#+END_SRC
** Changing the PDFs viewer
This module provides integration for four supported pdf viewers. They are
+ [[https://skim-app.sourceforge.io/][Skim.app]] (MacOS only)
+ Okular
+ Zathura
+ pdf-tools (requires =:tools pdf= module)
They are searched for in this order. See ~+latex-viewers~ to change the order,
or remove tools from the search altogether. If you want to exclusively use one
tool, for instance:
#+BEGIN_SRC emacs-lisp
(setq +latex-viewers '(zathura))
#+END_SRC
If none of these tools are found, ~latex-preview-pane~ (uses ~DocView~ in Emacs)
is used as a fallback. You can use this exclusively by setting ~+latex-viewers~
to ~nil~.

View file

@ -0,0 +1,49 @@
;;; lang/latex/autoload.el -*- lexical-binding: t; -*-
;;;###autoload
(defun +latex/LaTeX-indent-item ()
"Provide proper indentation for LaTeX \"itemize\",\"enumerate\", and \"description\" environments.
\"\\item\" is indented `LaTeX-indent-level' spaces relative to
the the beginning of the environment.
Continuation lines are indented either twice
`LaTeX-indent-level', or `LaTeX-indent-level-item-continuation'
if the latter is bound."
(save-match-data
(let* ((offset LaTeX-indent-level)
(contin (or (and (boundp '+latex-indent-level-item-continuation)
+latex-indent-level-item-continuation)
(* 4 offset)))
(re-beg "\\\\begin{")
(re-end "\\\\end{")
(re-env "\\(itemize\\|\\enumerate\\|description\\)")
(indent (save-excursion
(when (looking-at (concat re-beg re-env "}"))
(end-of-line))
(LaTeX-find-matching-begin)
(current-column))))
(cond ((looking-at (concat re-beg re-env "}"))
(or (save-excursion
(beginning-of-line)
(ignore-errors
(LaTeX-find-matching-begin)
(+ (current-column)
(if (looking-at (concat re-beg re-env "}"))
contin
offset))))
indent))
((looking-at (concat re-end re-env "}"))
indent)
((looking-at "\\\\item")
(+ offset indent))
((+ contin indent))))))
;;;###autoload
(defun +latex-symbols-company-backend (command &optional arg &rest _ignored)
"A wrapper backend for `company-mode' that either uses
`company-math-symbols-unicode' or `company-math-symbols-latex'. If
`+latex-enable-unicode-math' is non-nil use the former, otherwise the latter."
(if +latex-enable-unicode-math
(company-math-symbols-unicode command arg)
(company-math-symbols-latex command arg)))

View file

@ -1,88 +1,141 @@
;;; lang/latex/config.el -*- lexical-binding: t; -*-
(defvar +latex-bibtex-dir "~/work/writing/biblio/"
"Where bibtex files are kept.")
(defvar +latex-indent-level-item-continuation 4
"Custom indentation level for items in enumeration-type environments")
(defvar +latex-bibtex-default-file "default.bib"
"TODO")
(defvar +latex-bibtex-file nil
"File AUCTeX (specifically RefTeX) uses to search for citations.")
(defvar +latex-enable-unicode-math nil
"If non-nil, use `company-math-symbols-unicode' backend in LaTeX-mode,
enabling unicode symbols in math regions. This requires the unicode-math latex
package to be installed.")
(defvar +latex-viewers `(skim sumatrapdf zathura okular pdf-tools)
"A list of enabled latex viewers to use, in this order. If they don't exist,
they will be ignored. Recognized viewers are skim, zathura, okular and
pdf-tools.
If no viewers are found, `latex-preview-pane' is used.")
;;
(defvar +latex--company-backends nil)
;;
;; Plugins
;;
;; Packages
;; Because tex-mode is built-in and AucTex has conflicting components, we need
;; to ensure that auctex gets loaded instead of tex-mode.
(load "auctex" nil t)
(load "auctex-autoloads" nil t)
(push '("\\.[tT]e[xX]\\'" . TeX-latex-mode) auto-mode-alist)
(add-to-list 'auto-mode-alist '("\\.tex\\'" . TeX-latex-mode))
(add-transient-hook! 'LaTeX-mode-hook
(setq TeX-auto-save t
TeX-parse-self t
TeX-save-query nil
(after! tex
(setq TeX-parse-self t ; parse on load
TeX-auto-save t ; parse on save
;; use hidden dirs for auctex files
TeX-auto-local ".auctex-auto"
TeX-style-local ".auctex-style"
TeX-source-correlate-mode t
TeX-source-correlate-method 'synctex
;; don't start the emacs server when correlating sources
TeX-source-correlate-start-server nil
LaTeX-fill-break-at-separators nil
LaTeX-section-hook
;; automatically insert braces after sub/superscript in math mode
TeX-electric-sub-and-superscript t)
;; fontify common latex commands
(load! "+fontification")
;; select viewer
(load! "+viewers")
;; prompt for master
(setq-default TeX-master nil)
;; set-up chktex
(setcar (cdr (assoc "Check" TeX-command-list)) "chktex -v6 -H %s")
;; tell emacs how to parse tex files
(setq-hook! 'TeX-mode-hook ispell-parser 'tex)
;; Enable word wrapping
(add-hook 'TeX-mode-hook #'visual-line-mode)
;; Fold TeX macros
(add-hook 'TeX-mode-hook #'TeX-fold-mode)
;; Enable rainbow mode after applying styles to the buffer
(add-hook 'TeX-mode-hook #'rainbow-delimiters-mode)
;; display output of latex commands in popup
(set-popup-rule! " output\\*$" :size 15)
;; Do not prompt for Master files, this allows auto-insert to add templates to
;; .tex files
(add-hook! 'TeX-mode-hook
;; Necessary because it is added as an anonymous, byte-compiled function
(remove-hook 'find-file-hook
(cl-find-if #'byte-code-function-p find-file-hook)
'local))
(add-hook 'latex-mode-local-vars-hook #'flyspell-mode!)
;; All these excess pairs dramatically slow down typing in latex buffers, so
;; we remove them. Let snippets do their job.
(after! smartparens-latex
(let ((modes '(tex-mode plain-tex-mode latex-mode LaTeX-mode)))
(dolist (open '("\\left(" "\\left[" "\\left\\{" "\\left|"
"\\bigl(" "\\biggl(" "\\Bigl(" "\\Biggl(" "\\bigl["
"\\biggl[" "\\Bigl[" "\\Biggl[" "\\bigl\\{" "\\biggl\\{"
"\\Bigl\\{" "\\Biggl\\{"
"\\lfloor" "\\lceil" "\\langle"
"\\lVert" "\\lvert" "`"))
(sp-local-pair modes open nil :actions :rem))
(sp-local-pair modes "``" nil :unless '(:add sp-in-math-p)))))
(after! latex
(setq LaTeX-section-hook ; Add the toc entry to the sectioning hooks.
'(LaTeX-section-heading
LaTeX-section-title
LaTeX-section-toc
LaTeX-section-section
LaTeX-section-label))
(add-hook! (latex-mode LaTeX-mode) #'turn-on-auto-fill)
(add-hook! 'LaTeX-mode-hook #'(LaTeX-math-mode TeX-source-correlate-mode))
(set! :popup " output\\*$" :regexp t :size 15 :noselect t :autoclose t :autokill t)
(map! :map LaTeX-mode-map "C-j" nil)
(def-package! company-auctex
:when (featurep! :completion company)
:init
(set! :company-backend 'LaTeX-mode '(company-auctex))))
LaTeX-section-label)
LaTeX-fill-break-at-separators nil
LaTeX-item-indent 0)
(when +latex--company-backends
(set-company-backend! 'latex-mode +latex--company-backends))
;; Set custom item indentation
(dolist (env '("itemize" "enumerate" "description"))
(add-to-list 'LaTeX-indent-environment-list `(,env +latex/LaTeX-indent-item))))
(def-package! reftex ; built-in
:commands (turn-on-reftex reftex-mode)
(def-package! preview
:hook (LaTeX-mode . LaTeX-preview-setup)
:config
(setq-default preview-scale 1.4
preview-scale-function
(lambda () (* (/ 10.0 (preview-document-pt)) preview-scale))))
;; Nicely indent lines that have wrapped when visual line mode is activated
(def-package! adaptive-wrap
:hook (LaTeX-mode . adaptive-wrap-prefix-mode)
:init (setq-default adaptive-wrap-extra-indent 0))
(def-package! auctex-latexmk
:when (featurep! +latexmk)
:after latex
:init
(setq reftex-plug-into-AUCTeX t
reftex-default-bibliography (list +latex-bibtex-default-file)
reftex-toc-split-windows-fraction 0.2)
(add-hook! (latex-mode LaTeX-mode) #'turn-on-reftex)
;; Pass the -pdf flag when TeX-PDF-mode is active
(setq auctex-latexmk-inherit-TeX-PDF-mode t)
;; Set LatexMk as the default
(setq-hook! LaTeX-mode TeX-command-default "LatexMk")
:config
(map! :map reftex-mode-map
:localleader :n ";" 'reftex-toc)
(add-hook! 'reftex-toc-mode-hook
(reftex-toc-rescan)
(doom-hide-modeline-mode +1)
(map! :local
:e "j" #'next-line
:e "k" #'previous-line
:e "q" #'kill-buffer-and-window
:e "ESC" #'kill-buffer-and-window)))
;; Add latexmk as a TeX target
(auctex-latexmk-setup))
(def-package! bibtex ; built-in
(def-package! company-auctex
:when (featurep! :completion company)
:defer t
:config
(setq bibtex-dialect 'biblatex
bibtex-align-at-equal-sign t
bibtex-text-indentation 20
bibtex-completion-bibliography (list +latex-bibtex-default-file))
:init
(add-to-list '+latex--company-backends #'company-auctex-environments nil #'eq)
(add-to-list '+latex--company-backends #'company-auctex-macros nil #'eq))
(map! :map bibtex-mode-map "C-c \\" #'bibtex-fill-entry))
(def-package! company-math
:when (featurep! :completion company)
:defer t
:init
(add-to-list '+latex--company-backends #'+latex-symbols-company-backend nil #'eq))
(def-package! ivy-bibtex
:when (featurep! :completion ivy)
:commands ivy-bibtex)
(def-package! helm-bibtex
:when (featurep! :completion helm)
:commands helm-bibtex)
;; bibtex + reftex
(load! "+ref")

View file

@ -2,11 +2,22 @@
;;; lang/latex/packages.el
(package! auctex)
;; (package! auctex-latexmk)
(package! adaptive-wrap)
(package! latex-preview-pane)
;; Optional module features:
(when (featurep! +latexmk)
(package! auctex-latexmk))
;; Features according to other user selected options
(when (featurep! :completion company)
(package! company-auctex))
(package! company-auctex)
(package! company-reftex)
(package! company-math))
(when (featurep! :completion ivy)
(package! ivy-bibtex))
(when (featurep! :completion helm)
(package! helm-bibtex))

View file

@ -1,15 +1,57 @@
;;; lang/ledger/config.el -*- lexical-binding: t; -*-
(def-package! ledger-mode
:mode "\\.ledger$"
:config (setq ledger-clear-whole-transactions 1))
;; `ledger-mode'
(setq ledger-clear-whole-transactions 1)
(defun +ledger*check-version (orig-fn)
"Fail gracefully if ledger binary isn't available."
(if (executable-find ledger-binary-path)
(funcall orig-fn)
(message "Couldn't find '%s' executable" ledger-binary-path)))
(advice-add #'ledger-check-version :around #'+ledger*check-version)
(def-package! evil-ledger
:when (featurep! :feature evil)
:hook (ledger-mode . evil-ledger-mode))
;; Restore leader key in ledger reports
(map! :after ledger-mode
:map ledger-report-mode-map
"C-c C-c" #'ledger-report-edit-report
"C-c C-r" #'ledger-report-redo
"C-c C-s" #'ledger-report-save
:map ledger-reconcile-mode-map
[tab] #'ledger-reconcile-toggle)
(def-package! flycheck-ledger
:when (featurep! :feature syntax-checker)
:init (add-hook 'ledger-mode-hook #'flycheck-mode))
:when (featurep! :tools flycheck)
:after ledger-mode)
(def-package! evil-ledger
:when (featurep! :feature evil +everywhere)
:hook (ledger-mode . evil-ledger-mode)
:config
(set-evil-initial-state! 'ledger-report-mode 'normal)
(map! :map ledger-report-mode-map
:n "q" #'ledger-report-quit
:n "RET" #'ledger-report-edit-report
:n "gd" #'ledger-report-visit-source
:n "gr" #'ledger-report-redo
:map ledger-mode-map
:m "]]" #'ledger-navigate-next-xact-or-directive
:m "[[" #'ledger-navigate-prev-xact-or-directive
:localleader
:map ledger-mode-map
"a" #'ledger-add-transaction
"t" #'ledger-toggle-current
"d" #'ledger-delete-current-transaction
"r" #'ledger-report
"R" #'ledger-reconcile
"s" #'ledger-sort-region
"S" #'ledger-schedule-upcoming
(:prefix "g"
"s" #'ledger-display-ledger-stats
"b" #'ledger-display-balance-at-point))
;; Fix inaccurate keybind message
(defun +ledger*fix-key-help (&rest _)
(message "q to quit; gr to redo; RET to edit; C-c C-s to save"))
(advice-add #'ledger-report :after #'+ledger*fix-key-help))

View file

@ -6,5 +6,5 @@
(when (featurep! :feature evil)
(package! evil-ledger))
(when (featurep! :feature syntax-checker)
(when (featurep! :tools flycheck)
(package! flycheck-ledger))

View file

@ -1,7 +1,7 @@
;;; lang/lua/autoload.el -*- lexical-binding: t; -*-
;;;###autoload
(defun +lua/repl ()
(defun +lua/open-repl ()
"Open Lua REPL."
(interactive)
(lua-start-process "lua" "lua")
@ -11,9 +11,10 @@
(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)))))
(when-let* ((root (locate-dominating-file buffer-file-name "main.lua")))
(async-shell-command
(format "%s %s"
(or (executable-find "love")
(if IS-MAC "open -a love.app"))
(shell-quote-argument (file-name-directory root))))))

View file

@ -1,42 +1,35 @@
;;; lang/lua/config.el --- lua + Love2D -*- lexical-binding: t; -*-
;;; lang/lua/config.el -*- lexical-binding: t; -*-
;; sp's default rules are obnoxious, so disable them
(provide 'smartparens-lua)
;;
;; Major modes
(def-package! lua-mode
:mode "\\.lua$"
:interpreter "lua"
:defer t
:init
;; lua-indent-level defaults to 3 otherwise. Madness.
(setq lua-indent-level tab-width)
:config
(add-hook 'lua-mode-hook #'flycheck-mode)
(set! :electric 'lua-mode :words '("else" "end"))
(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))
(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))
(set-lookup-handlers! 'lua-mode :documentation 'lua-search-documentation)
(set-electric! 'lua-mode :words '("else" "end"))
(set-repl-handler! 'lua-mode #'+lua/open-repl)
(set-company-backend! 'lua-mode '(company-lua company-yasnippet)))
(def-package! company-lua
:after (:all company lua-mode)
:config
(set! :company-backend 'lua-mode '(company-lua company-yasnippet)))
(def-package! moonscript
:mode ("\\.moon$" . moonscript-mode)
:config (defvaralias 'moonscript-indent-offset 'tab-width))
;;;###package moonscript
(setq-hook! 'moonscript-mode-hook moonscript-indent-offset tab-width)
;;
;; Frameworks
;;
;;; Frameworks
(def-project-mode! +lua-love-mode
:modes (lua-mode markdown-mode json-mode)
:files (and "main.lua" "conf.lua"))
:files (and "main.lua" "conf.lua")
:on-load
(map! :localleader
:map +lua-love-mode-map
"b" #'+lua/run-love-game))

View file

@ -11,7 +11,7 @@
(let ((delim "~~"))
(if (markdown-use-region-p)
;; Active region
(cl-destructuring-bind (beg end)
(cl-destructuring-bind (beg . end)
(markdown-unwrap-things-in-region
(region-beginning) (region-end)
+markdown--regex-del 2 4)
@ -21,3 +21,22 @@
(markdown-unwrap-thing-at-point nil 2 4)
(markdown-wrap-or-insert delim delim 'word nil nil)))))
;;;###autoload
(defun +markdown-flyspell-word-p ()
"Return t if point is on a word that should be spell checked.
Return nil if on a link url, markup, html, or references."
(let ((faces (doom-enlist (get-text-property (point) 'face))))
(or (and (memq 'font-lock-comment-face faces)
(memq 'markdown-code-face faces))
(not (cl-loop with unsafe-faces = '(markdown-reference-face
markdown-url-face
markdown-markup-face
markdown-comment-face
markdown-html-attr-name-face
markdown-html-attr-value-face
markdown-html-tag-name-face
markdown-code-face)
for face in faces
if (memq face unsafe-faces)
return t)))))

View file

@ -1,53 +1,57 @@
;;; lang/markdown/config.el -*- lexical-binding: t; -*-
(def-package! markdown-mode
:mode "/README$"
:mode "\\.m\\(d\\|arkdown\\)$"
:mode ("/README\\.md$" . gfm-mode)
:mode ("/README\\(?:\\.\\(?:markdown\\|md\\)\\)?\\'" . gfm-mode)
:init
(setq markdown-enable-wiki-links t
markdown-enable-math t
markdown-italic-underscore t
markdown-asymmetric-header t
markdown-make-gfm-checkboxes-buttons t
markdown-gfm-additional-languages '("sh")
markdown-fontify-code-blocks-natively t
markdown-hide-urls nil) ; trigger with `markdown-toggle-url-hiding'
markdown-hide-urls nil ; trigger with `markdown-toggle-url-hiding'
markdown-enable-math t ; syntax highlighting for latex fragments
markdown-gfm-uppercase-checkbox t) ; for compat with org-mode
:config
(add-hook! markdown-mode
(auto-fill-mode +1)
(setq line-spacing 2
fill-column 80))
(set-flyspell-predicate! '(markdown-mode gfm-mode)
#'+markdown-flyspell-word-p)
(set-lookup-handlers! '(markdown-mode gfm-mode)
:file #'markdown-follow-thing-at-point)
(map! (:map markdown-mode-map
[remap find-file-at-point] #'markdown-follow-thing-at-point
"M-*" #'markdown-insert-list-item
"M-b" #'markdown-insert-bold
"M-i" #'markdown-insert-italic
"M-`" #'+markdown/insert-del
:m "gj" #'markdown-next-visible-heading
:m "gk" #'markdown-previous-visible-heading
;; Assumes you have a markdown renderer plugin in chrome
:n "M-r" #'browse-url-of-file
(add-hook 'markdown-mode-hook #'auto-fill-mode)
(sp-with-modes '(markdown-mode gfm-mode)
(sp-local-pair "```" "```" :post-handlers '(:add ("||\n[i]" "RET"))))
(map! :map markdown-mode-map
:i "M-*" #'markdown-insert-list-item
:i "M-b" #'markdown-insert-bold
:i "M-i" #'markdown-insert-italic
:i "M-`" #'+markdown/insert-del
(:when (featurep! :feature evil +everywhere)
:m "gj" #'markdown-next-visible-heading
:m "gk" #'markdown-previous-visible-heading
;; TODO: Make context sensitive
:m "]h" #'markdown-next-visible-heading
:m "[h" #'markdown-previous-visible-heading
:m "[p" #'markdown-promote
:m "]p" #'markdown-demote
:m "[l" #'markdown-next-link
:m "]l" #'markdown-previous-link
:i "M--" #'markdown-insert-hr
(:localleader
:nv "o" #'markdown-open
:nv "b" #'markdown-preview
(:prefix "i"
:nv "t" #'markdown-toc-generate-toc
:nv "i" #'markdown-insert-image
:nv "l" #'markdown-insert-link)))))
:m "]h" #'markdown-next-visible-heading
:m "[h" #'markdown-previous-visible-heading
:m "[p" #'markdown-promote
:m "]p" #'markdown-demote
:m "[l" #'markdown-previous-link
:m "]l" #'markdown-next-link
:i "M--" #'markdown-insert-hr
:n "M-r" #'browse-url-of-file)
(:localleader
"o" #'markdown-open
"b" #'markdown-preview
(:prefix "i"
"t" #'markdown-toc-generate-toc
"i" #'markdown-insert-image
"l" #'markdown-insert-link))))
(def-package! markdown-toc
:commands markdown-toc-generate-toc)
(def-package! pandoc-mode
:when (featurep! +pandoc)
:commands pandoc-mode
:hook (markdown-mode . conditionally-turn-on-pandoc)
:init (setq markdown-command "pandoc --from=markdown --to=html --standalone --mathjax --highlight-style=pygments"))

View file

@ -0,0 +1,11 @@
;; -*- lexical-binding: t; no-byte-compile: t; -*-
;;; lang/markdown/doctor.el
(when (featurep! +pandoc)
(unless (executable-find "pandoc")
(warn! "Couldn't find pandoc, markdown-mode may have issues")))
(when (require 'markdown-mode nil t)
(unless (executable-find markdown-command)
(warn! "Couldn't find %S, can't export markdown to html"
markdown-command)))

View file

@ -4,3 +4,7 @@
(package! markdown-mode)
(package! markdown-toc)
(when (featurep! +pandoc)
(package! pandoc-mode))

View file

@ -0,0 +1,47 @@
#+TITLE: :lang Nim
#+begin_quote
This module is a work in progress.
#+end_quote
This module adds [[https://nim-lang.org][Nim]] support to Emacs.
+ Code completion (nimsuggest + company)
+ Syntax checking (nimsuggest + flycheck)
+ Babel support (~ob-nim~)
* Table of Contents :TOC:
- [[Module Flags][Module Flags]]
- [[Prerequisites][Prerequisites]]
- [[Nim][Nim]]
- [[Configuration][Configuration]]
* Module Flags
This module provides no flags.
* Prerequisites
+ ~nim~ (for building & evaluation)
+ ~nimsuggest~ (for code completion, syntax checking & jump-to-definition functionality)
** Nim
=choosenim= is an installer and version manager for the Nim programming
language. You can install the latest stable release of Nim by running the
following in your terminal and following the onscreen instructions:
#+BEGIN_SRC bash
curl https://nim-lang.org/choosenim/init.sh -sSf | sh
#+END_SRC
Alternatively, nim is usually available through your OS's package manager:
*** MacOS
#+BEGIN_SRC sh :tangle (if (doom-system-os 'macos) "yes")
brew install nim
#+END_SRC
*** Arch Linux
#+BEGIN_SRC sh :dir /sudo:: :tangle (if (doom-system-os 'arch) "yes")
sudo pacman --needed --noconfirm -S nim nimble
#+END_SRC
* Configuration

View file

@ -0,0 +1,42 @@
;;; lang/nim/config.el -*- lexical-binding: t; -*-
(after! nim-mode
(defun +nim|init-nimsuggest-mode ()
"Conditionally load `nimsuggest-mode', instead of clumsily erroring out if
nimsuggest isn't installed."
(unless (stringp nimsuggest-path)
(setq nimsuggest-path (executable-find "nimsuggest")))
(when (and nimsuggest-path (file-executable-p nimsuggest-path))
(nimsuggest-mode)))
(add-hook 'nim-mode-hook #'+nim|init-nimsuggest-mode)
(when IS-WINDOWS
;; TODO File PR/report upstream (https://github.com/nim-lang/nim-mode)
(defun doom*nimsuggest--get-dirty-dir ()
"The original `nimsuggest--get-dirty-dir' incorrectly extracts the frame
number from the string representation of `selected-frame', which can contain
characters that are illegal on Windows, causing invalid argument errors when
`nimsuggest--make-tempdir' tries to use it."
(let* ((frame-str (format "%s" (selected-frame)))
(frame-num-str (if (string-match " \\(0x[0-9a-z]+\\)>$" frame-str)
(match-string 1 frame-str))))
(file-name-as-directory (concat nimsuggest-dirty-directory frame-num-str))))
(advice-add #'nimsuggest--get-dirty-dir :override #'doom*nimsuggest--get-dirty-dir)
;; TODO File PR/report upstream (https://github.com/nim-lang/nim-mode)
(defun doom*nimsuggest--get-temp-file-name (path)
"Removes invalid characters from the temp file path, including the unicode
character that colon is replaced with, which is known to cause issues on
windows."
(replace-regexp-in-string "[* |<>\"?*]" "" path))
(advice-add #'nimsuggest--get-temp-file-name :filter-return #'doom*nimsuggest--get-temp-file-name))
(map! :localleader
:map nim-mode-map
"b" #'nim-compile))
(def-package! flycheck-nim
:when (featurep! :tools flycheck)
:after nim-mode)

View file

@ -0,0 +1,9 @@
;; -*- lexical-binding: t; no-byte-compile: t; -*-
;;; lang/nim/doctor.el
(unless (executable-find "nimsuggest")
(warn! "Could not find nimsuggest executable; code-completion, syntax checking and jump-to-definition functionality will be disabled."))
(unless (executable-find "nim")
(warn! "Could not find nim executable; build commands will be disabled."))

View file

@ -0,0 +1,9 @@
;; -*- no-byte-compile: t; -*-
;;; lang/nim/packages.el
;;; requires nim nimsuggest nimble
(package! nim-mode)
(when (featurep! :tools flycheck)
(package! flycheck-nim))

View file

@ -1,4 +1,28 @@
;;; lang/nix/config.el -*- lexical-binding: t; -*-
(def-package! nix-mode
:mode "\\.nix$")
:mode "\\.nix\\'"
:config
(set-company-backend! 'nix-mode 'company-nixos-options)
(setq nix-indent-function #'nix-indent-line)
(map! :localleader
:map nix-mode-map
"f" #'nix-update-fetch
"p" #'nix-format-buffer
"r" #'nix-repl-show
"s" #'nix-shell
"b" #'nix-build
"u" #'nix-unpack
(:when (featurep! :completion helm)
"o" #'helm-nixos-options)))
(def-package! nix-drv-mode
:mode "\\.drv\\'")
(def-package! nix-update
:commands nix-update-fetch)
(def-package! nix-repl
:commands nix-repl-show)

View file

@ -0,0 +1,9 @@
;; -*- lexical-binding: t; no-byte-compile: t; -*-
;;; lang/nix/doctor.el
(unless (executable-find "nix")
(warn! "Couldn't find the nix package manager. nix-mode won't work."))
(unless (executable-find "nixfmt")
(warn! "Couldn't find nixfmt. nix-format-buffer won't work."))

Some files were not shown because too many files have changed in this diff Show more