You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
501 lines
16 KiB
501 lines
16 KiB
;;; dot-development.el --- -*- lexical-binding: t; -*- |
|
|
|
;;; Commentary: |
|
|
|
;; Development. |
|
|
|
;;; Code: |
|
|
|
;; ----------------------------------------- |
|
;; Company |
|
|
|
(elpaca-setup company |
|
(:require company) |
|
(:with-mode |
|
(c-mode-common |
|
emacs-lisp-mode |
|
latex-mode |
|
org-mode |
|
php-mode |
|
shell-mode |
|
shell-script-mode) |
|
(:hook company-mode)) |
|
(:when-loaded |
|
(setq company-idle-delay 0.2) |
|
(setq company-minimum-prefix-length 2) |
|
(setq company-show-numbers t) |
|
(setq company-tooltip-align-annotations 't))) |
|
|
|
;; Sort Company completions. |
|
|
|
(elpaca-setup company-prescient |
|
(:load-after company prescient) |
|
(:when-loaded (company-prescient-mode))) |
|
|
|
;; Auto-completion for C/C++ headers. |
|
|
|
(elpaca-setup company-c-headers |
|
(:when-loaded (add-to-list 'company-backends 'company-c-headers))) |
|
|
|
;; GLSL integration with company requires the package: ~glslang~. |
|
|
|
(when (executable-find "glslangValidator") |
|
(elpaca-setup company-glsl |
|
(:when-loaded (add-to-list 'company-backends 'company-glsl)))) |
|
|
|
;; ----------------------------------------- |
|
;; Git |
|
|
|
(elpaca-setup diff-hl |
|
(:require diff-hl) |
|
(:with-mode prog-mode |
|
(:hook turn-on-diff-hl-mode) |
|
(:hook dot/diff-hl-enable-flydiff-and-fringe)) |
|
(:when-loaded |
|
|
|
(defun dot/diff-hl-enable-flydiff-and-fringe () |
|
"Enable on the fly diff checking if file is under version control." |
|
(let ((buffer buffer-file-name)) |
|
(when (and buffer (vc-registered buffer)) |
|
(diff-hl-flydiff-mode) |
|
(dot/toggle-fringe 1)))))) |
|
|
|
(elpaca-setup transient |
|
(:when-loaded |
|
(setq transient-history-file (expand-file-name "transient/history.el" dot-cache-dir)) |
|
(setq transient-values-file (expand-file-name "transient/values.el" dot-cache-dir)))) |
|
|
|
(elpaca-setup magit |
|
(:autoload magit-status magit-status-here) |
|
(:with-mode git-commit-setup |
|
(:hook git-commit-turn-on-auto-fill) |
|
(:hook git-commit-turn-on-flyspell)) |
|
(:with-mode magit-pre-refresh (:hook diff-hl-magit-pre-refresh)) |
|
(:with-mode magit-post-refresh (:hook diff-hl-magit-post-refresh)) |
|
(:load-after diff-hl transient) |
|
(:when-loaded |
|
(setq git-commit-fill-column 72) |
|
(setq git-commit-summary-max-length 72) |
|
(setq magit-completing-read-function #'completing-read) |
|
(setq magit-diff-paint-whitespace-lines 'both) |
|
(setq magit-display-buffer-function #'magit-display-buffer-same-window-except-diff-v1) |
|
(setq magit-process-extreme-logging nil) |
|
(setq magit-repository-directories '(("~/dotfiles" . 0) |
|
("~/code" . 3))) |
|
|
|
(put 'magit-log-select-pick :advertised-binding [?\M-c]) |
|
(put 'magit-log-select-quit :advertised-binding [?\M-k]) |
|
|
|
(defun dot/magit-select-repo () |
|
"Select project repo." |
|
(interactive) |
|
(let ((current-prefix-arg '(t))) |
|
(call-interactively #'magit-status))))) |
|
|
|
(elpaca-setup magit-todos |
|
(:load-after magit) |
|
(:when-loaded |
|
(magit-todos-mode))) |
|
|
|
;; ----------------------------------------- |
|
;; Project |
|
|
|
;; Project manager. |
|
|
|
;; Adding to project.el project directory detection |
|
;; https://michael.stapelberg.ch/posts/2021-04-02-emacs-project-override/ |
|
|
|
(elpaca-nil (setup project ; built-in |
|
(setq project-list-file (expand-file-name "projects" dot-cache-dir)) |
|
(:when-loaded |
|
|
|
(defun dot/project-find (dir) |
|
(let ((root (locate-dominating-file dir ".project"))) |
|
(and root (list 'vc 'Filewise root)))) |
|
(add-hook 'project-find-functions #'dot/project-find) |
|
|
|
(defun dot/find-project-root () |
|
"Return root of the project, determined by `.git/' and `.project', |
|
`default-directory' otherwise." |
|
(let ((project (project-current))) |
|
(if project |
|
(project-root project) |
|
default-directory))) |
|
|
|
(defun dot/find-file-in-project-root () |
|
"Find file in project root." |
|
(interactive) |
|
(let ((default-directory (dot/find-project-root))) |
|
(call-interactively 'find-file))) |
|
|
|
(defun dot/project-remember-projects-under (dir maxdepth) |
|
"Index all projects below directory DIR recursively, until MAXDEPTH." |
|
(let ((files (mapcar 'file-name-directory |
|
(dot/directory-files-recursively-depth |
|
dir "\\.git$\\|\\.project$" t maxdepth)))) |
|
(dolist (path files) |
|
(project-remember-projects-under path)))) |
|
|
|
(unless (file-exists-p project-list-file) |
|
(project-remember-projects-under "~/dotfiles") |
|
(dot/project-remember-projects-under "~/code" 4)) |
|
|
|
(defun dot/project-project-name () |
|
"Return project name." |
|
(let ((project (project-current))) |
|
(if project |
|
(let* ((project (file-truename (directory-file-name (project-root (project-current))))) |
|
(parent-dir-full (file-name-directory (directory-file-name project))) |
|
(parent-dir (file-name-nondirectory (substring parent-dir-full 0 -1))) |
|
(filename (file-name-nondirectory project))) |
|
(concat filename "/" parent-dir)) |
|
"-"))) |
|
|
|
(defun dot/project-save-project-buffers () |
|
"Save all project buffers." |
|
(interactive) |
|
(let ((buffers (cl-remove-if (lambda (buffer) (not (buffer-file-name buffer))) |
|
(project-buffers (project-current))))) |
|
(save-some-buffers t (lambda () (member (current-buffer) buffers)))))))) |
|
|
|
;; ----------------------------------------- |
|
;; Compile |
|
|
|
;; Enable color escape codes. |
|
|
|
(elpaca-nil (setup ansi-color ; built-in |
|
(:with-mode compilation-filter (:hook ansi-color-compilation-filter)) |
|
;; :hook (compilation-filter . ansi-color-compilation-filter) |
|
(:when-loaded (setq ansi-color-bold-is-bright t)))) |
|
|
|
(elpaca-nil (setup compile ; built-in |
|
(defun dot/compile-disable-underline () "" |
|
(face-remap-add-relative 'underline :underline nil)) |
|
(:with-mode comint-mode (:hook dot/compile-disable-underline)) |
|
(:when-loaded |
|
(setq compilation-scroll-output 'first-error) |
|
|
|
(defun dot/compile () |
|
"Compile project." |
|
(interactive) |
|
(let ((default-directory (dot/find-project-root))) |
|
(dot/project-save-project-buffers) |
|
(let ((current-prefix-arg '(t))) |
|
(call-interactively 'compile))))))) |
|
|
|
;; ----------------------------------------- |
|
;; Languages |
|
|
|
;;; Language Server Protocol |
|
|
|
(elpaca-setup lsp-mode |
|
(:autoload lsp-deferred) |
|
;; (:require lsp-modeline lsp-mode) |
|
(:with-mode |
|
(c-mode ; clangd |
|
c++-mode ; clangd |
|
php-mode ; nodejs-intelephense |
|
csharp-mode ; omnisharp-roslyn-bin |
|
go-mode ; gopls |
|
kotlin-mode ; kotlin-language-server |
|
lua-mode ; lua-language-server |
|
latex-mode ; texlab |
|
swift-mode ; swift-bin |
|
web-mode) |
|
(:hook lsp-deferred)) |
|
(:when-loaded |
|
(setq lsp-auto-guess-root t) |
|
(setq lsp-clients-clangd-args '("-j=2" |
|
"--background-index" |
|
"--clang-tidy" |
|
"--compile-commands-dir=build" |
|
"--log=error" |
|
"--header-insertion-decorators=0" |
|
"--pch-storage=memory" |
|
"--enable-config")) |
|
(setq lsp-csharp-omnisharp-roslyn-binary-path "/usr/bin/omnisharp") |
|
(setq lsp-csharp-server-install-dir "/usr/lib/omnisharp/") |
|
(setq lsp-clients-lua-language-server-bin "/usr/bin/lua-language-server") |
|
(setq lsp-clients-lua-language-server-install-dir "/usr/lib/lua-language-server/") |
|
(setq lsp-clients-lua-language-server-main-location "/usr/lib/lua-language-server/main.lua") |
|
(setq lsp-enable-xref t) |
|
(setq lsp-headerline-breadcrumb-enable nil) |
|
(setq lsp-intelephense-storage-path (expand-file-name "lsp-cache" dot-cache-dir)) |
|
(setq lsp-keep-workspace-alive nil) |
|
;; (setq lsp-modeline-code-actions-enable nil) |
|
;; (setq lsp-modeline-diagnostics-enable nil) |
|
;; (setq lsp-modeline-workspace-status-enable nil) |
|
(setq lsp-prefer-flymake nil) |
|
(setq lsp-session-file (expand-file-name "lsp-session-v1" dot-cache-dir)) |
|
|
|
;; Mark clangd args variable as safe to modify via .dir-locals.el |
|
(put 'lsp-clients-clangd-args 'safe-local-variable #'listp) |
|
|
|
;; Enable which-key descriptions |
|
(dolist (leader-key (list dot/leader-key dot/leader-alt-key)) |
|
(let ((lsp-keymap-prefix (concat leader-key " l"))) |
|
(lsp-enable-which-key-integration))) |
|
|
|
(defun dot/lsp-format-buffer-or-region () |
|
"Format the selection (or buffer) with LSP." |
|
(interactive) |
|
(unless (bound-and-true-p lsp-mode) |
|
(message "Not in an LSP buffer")) |
|
(call-interactively |
|
(if (use-region-p) |
|
#'lsp-format-region |
|
#'lsp-format-buffer))) |
|
|
|
;; This is cached to prevent unneeded I/O |
|
(setq lsp-in-cpp-project-cache nil) |
|
(defun dot/lsp-format-cpp-buffer () |
|
"Format buffer in C++ projects." |
|
(unless lsp-in-cpp-project-cache |
|
(set (make-local-variable 'lsp-in-cpp-project-cache) |
|
(list |
|
(if (and (eq major-mode 'c++-mode) |
|
(bound-and-true-p lsp-mode) |
|
(or |
|
(locate-dominating-file "." ".clang-format") |
|
(locate-dominating-file "." "_clang-format"))) |
|
t |
|
nil)))) |
|
(when (car lsp-in-cpp-project-cache) |
|
(lsp-format-buffer))) |
|
(add-hook 'before-save-hook #'dot/lsp-format-cpp-buffer))) |
|
|
|
(elpaca-setup lsp-ui |
|
(:autoload lsp-ui-mode) |
|
(:load-after flycheck lsp-mode) |
|
(:when-loaded |
|
(setq lsp-ui-doc-border (face-foreground 'default)) |
|
(setq lsp-ui-doc-delay 0.5) |
|
(setq lsp-ui-doc-enable t) |
|
(setq lsp-ui-doc-header t) |
|
(setq lsp-ui-doc-include-signature t) |
|
(setq lsp-ui-doc-position 'top) |
|
(setq lsp-ui-doc-use-childframe t) |
|
(setq lsp-ui-flycheck-list-position 'right) |
|
(setq lsp-ui-imenu-enable nil) |
|
(setq lsp-ui-peek-enable nil) |
|
(setq lsp-ui-sideline-enable nil))) |
|
|
|
;;; Debug Adapter Protocol |
|
|
|
(elpaca-setup treemacs |
|
(:hook dot/hook-disable-line-numbers) |
|
(:when-loaded (setq treemacs-persist-file (expand-file-name "treemacs/persist" dot-cache-dir)))) |
|
|
|
(elpaca-setup lsp-treemacs |
|
(:load-after treemacs) |
|
(:when-loaded (setq lsp-treemacs-error-list-current-project-only t))) |
|
|
|
(elpaca-setup dap-mode |
|
(:with-mode lsp-after-initialize (:hook dot/dap-install-debug-adapters)) |
|
(:load-after lsp-treemacs lsp-mode) |
|
(:when-loaded |
|
(setq dap-auto-configure-features '(sessions locals expressions controls tooltip)) |
|
(setq dap-breakpoints-file (expand-file-name "dap/breakpoints" dot-cache-dir)) |
|
(setq dap-utils-extension-path (expand-file-name "dap" dot-cache-dir)) |
|
|
|
;; Create dap extension directory |
|
(unless (file-directory-p dap-utils-extension-path) |
|
(make-directory dap-utils-extension-path t)) |
|
|
|
(defun dot/dap-install-debug-adapters () |
|
"Install and Load debug adapters." |
|
(interactive) |
|
(unless (bound-and-true-p lsp-mode) |
|
(user-error "Not in an LSP buffer")) |
|
(when (string-equal major-mode "c++-mode") |
|
(require 'dap-cpptools) |
|
(dap-cpptools-setup))))) |
|
|
|
;;; C/C++ |
|
|
|
(elpaca-nil (setup c-mode ; built-in |
|
;; C++ // line comment style in c-mode |
|
(defun dot/c-mode-comment-style () "" |
|
(c-toggle-comment-style -1)) |
|
(:hook dot/c-mode-comment-style))) |
|
|
|
;;; C# |
|
|
|
;; Packages: |
|
;; - dotnet-host |
|
;; - dotnet-runtime-6.0 |
|
;; - dotnet-sdk-6.0 |
|
;; - dotnet-targeting-pack-6.0 |
|
;; - omnisharp-roslyn-bin |
|
;; - netcoredbg (edit PKGBUILD to detect dotnet -6.0 dependencies) |
|
|
|
(elpaca-nil (setup csharp-mode)) ; built-in |
|
|
|
;;; CMake |
|
|
|
(elpaca-setup cmake-mode |
|
(:defer 2) |
|
(:when-loaded (setq cmake-tab-width (default-value 'tab-width)))) |
|
|
|
;;; Emacs Lisp |
|
|
|
(elpaca-nil (setup emacs-lisp ; built-in |
|
(defun dot/elisp-init () "" |
|
(setq-local indent-tabs-mode nil)) |
|
(:hook dot/elisp-init))) |
|
|
|
;;; GLSL |
|
|
|
(elpaca-setup glsl-mode) |
|
|
|
;;; Golang |
|
|
|
(elpaca-setup go-mode) |
|
|
|
;;; HTML |
|
|
|
(elpaca-setup web-mode |
|
(:file-match "\\.ts") |
|
(:file-match "\\.vue")) |
|
|
|
;;; Kotlin |
|
|
|
(elpaca-setup kotlin-mode) |
|
|
|
;;; Lua |
|
|
|
(elpaca-setup lua-mode |
|
(:when-loaded (setq lua-indent-level (default-value 'tab-width)))) |
|
|
|
;;; PHP |
|
|
|
(elpaca-setup php-mode |
|
(defun dot/php-mode-init () "" |
|
(setq-local indent-tabs-mode t)) |
|
(:hook dot/php-mode-init)) |
|
|
|
(elpaca-setup restclient) |
|
(elpaca-setup restclient-jq |
|
(:load-after restclient)) |
|
|
|
;;; Python |
|
|
|
(elpaca-nil (setup python-mode ; built-in |
|
(defun dot/python-mode-init () "" |
|
(setq-local indent-tabs-mode t) |
|
(setq-local tab-width (default-value 'tab-width)) |
|
(setq python-indent-offset (default-value 'tab-width))) |
|
(:hook dot/python-mode-init))) |
|
|
|
;;; Swift |
|
|
|
(elpaca-setup swift-mode) |
|
(elpaca-setup lsp-sourcekit |
|
(:load-after lsp-mode) |
|
(:when-loaded |
|
(setq lsp-sourcekit-executable "/usr/bin/sourcekit-lsp"))) |
|
|
|
;;; YAML |
|
|
|
(elpaca-setup yaml-mode) |
|
;; :defer t) |
|
|
|
;; ----------------------------------------- |
|
;; Syntax Highlighting |
|
|
|
;; (elpaca-setup tree-sitter-langs)) |
|
|
|
;; (elpaca-setup tree-sitter) |
|
;; (:also-load tree-sitter-langs) |
|
;; (:when-loaded |
|
;; (global-tree-sitter-mode) |
|
;; (add-hook 'tree-sitter-after-on-hook #'tree-sitter-hl-mode))) |
|
|
|
;; ----------------------------------------- |
|
;; Quality of Life |
|
|
|
;;; Flycheck, on the fly syntax checking |
|
|
|
(elpaca-setup flycheck |
|
(:autoload flycheck-mode) |
|
(:with-mode |
|
(c-mode-common |
|
emacs-lisp-mode |
|
latex-mode |
|
org-mode |
|
php-mode |
|
sh-mode |
|
shell-mode |
|
shell-script-mode) |
|
(:hook flycheck-mode)) |
|
(:when-loaded |
|
(setq flycheck-clang-language-standard "c++20") |
|
(setq flycheck-gcc-language-standard "c++20"))) |
|
|
|
;; For .el files which are intended to be packages |
|
(elpaca-setup flycheck-package |
|
(:load-after flycheck) |
|
(:when-loaded |
|
(add-to-list 'flycheck-checkers 'flycheck-emacs-lisp-package) |
|
(flycheck-package-setup))) |
|
|
|
(elpaca-setup flycheck-clang-tidy |
|
(:load-after flycheck) |
|
(:with-mode flycheck-mode (:hook flycheck-clang-tidy-setup)) |
|
(:when-loaded (setq flycheck-clang-tidy-extra-options "--format-style=file"))) |
|
|
|
;;; Flyspell |
|
|
|
(elpaca-nil (setup ispell ; built-in |
|
(:when-loaded |
|
(setq ispell-program-name "/usr/bin/hunspell") |
|
(ispell-set-spellchecker-params) |
|
(ispell-hunspell-add-multi-dic "en_US,nl_NL") |
|
(setq ispell-dictionary "en_US,nl_NL")))) |
|
|
|
;; Give Flyspell a selection menu. |
|
(elpaca-setup flyspell-correct |
|
(:load-after flyspell) |
|
(:with-mode org-mode (:hook flyspell-mode)) |
|
(:when-loaded |
|
(setq flyspell-issue-message-flag nil) |
|
(setq flyspell-issue-welcome-flag nil)) |
|
|
|
(defun dot/flyspell-toggle () |
|
"Toggle Flyspell, prompt for language." |
|
(interactive) |
|
(if (symbol-value flyspell-mode) |
|
(flyspell-mode -1) |
|
(call-interactively 'ispell-change-dictionary) |
|
(if (derived-mode-p 'prog-mode) |
|
(flyspell-prog-mode) |
|
(flyspell-mode)) |
|
(flyspell-buffer)))) |
|
|
|
;;; Rainbow Delimiters |
|
|
|
(elpaca-setup rainbow-delimiters |
|
(:hook-into prog-mode)) |
|
|
|
;;; Rainbow Mode |
|
|
|
(elpaca-setup rainbow-mode |
|
(:hook-into css-mode)) |
|
|
|
;;; YASnippet |
|
|
|
(elpaca-setup yasnippet |
|
(:autoload yas-expand yas-insert-snippet) |
|
(setq yas-snippet-dirs (list (expand-file-name "snippets" dot-emacs-dir))) |
|
(setq yas-prompt-functions '(yas-completing-prompt)) |
|
(:when-loaded |
|
(yas-global-mode))) |
|
|
|
(elpaca-setup yasnippet-snippets |
|
(:load-after yasnippet)) |
|
|
|
;; https://stackoverflow.com/questions/22735895/configuring-a-yasnippet-for-two-scenarios-1-region-is-active-2-region-is |
|
|
|
(provide 'dot-development) |
|
|
|
;;; dot-org-mode.el ends here
|
|
|