This is a collection of dotfiles and scripts for my bspwm setup
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.
 
 
 
 
 
 

12 KiB

Development

Company

(use-package company
  :hook
  ((c-mode-common
	emacs-lisp-mode
	latex-mode
	org-mode
	php-mode
	shell-mode
	shell-script-mode)
   . company-mode)
  :config
  (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.

(use-package company-prescient
  :after (company prescient)
  :config (company-prescient-mode))

Auto-completion for C/C++ headers.

(use-package company-c-headers
  :after company
  :config (add-to-list 'company-backends 'company-c-headers))

GLSL integration with company requires the package: glslang.

(when (executable-find "glslangValidator")
  (use-package company-glsl
	:after company
	:config (add-to-list 'company-backends 'company-glsl)))

Git

(use-package diff-hl
  :demand
  :hook (prog-mode . turn-on-diff-hl-mode)
  :hook (prog-mode . dot/diff-hl-enable-flydiff-and-fringe)
  :config

  (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)))))

(use-package transient
  :defer t
  :config (setq transient-history-file (concat dot-cache-dir "/transient/history.el")))

(use-package magit
  :after (diff-hl transient)
  :hook (git-commit-setup . git-commit-turn-on-auto-fill)
  :hook (git-commit-setup . git-commit-turn-on-flyspell)
  :hook (magit-pre-refresh . diff-hl-magit-pre-refresh)
  :hook (magit-post-refresh . diff-hl-magit-post-refresh)
  :config
  (setq git-commit-fill-column 72)
  (setq git-commit-summary-max-length 70)
  (setq magit-completing-read-function #'selectrum-completing-read)
  (setq magit-diff-paint-whitespace-lines 'both)
  (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]))

Project

Project manager.

Adding to project.el project directory detection.

(use-package project
  :defer t
  :init (setq project-list-file (concat dot-cache-dir "/projects"))
  :config
  (defun dot/project-find (dir)
	(let ((root (locate-dominating-file dir ".project")))
	  (and root (cons 'vc 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
		  (file-name-nondirectory (directory-file-name (project-root project)))
		"-")))

  (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))))))

Languages

Language Server Support

Language Server Protocol.

(use-package lsp-mode
  :commands lsp
  :after which-key
  :hook
  ((c-mode         ; clangd
	c++-mode       ; clangd
	lua-mode       ; lua-language-server
	php-mode       ; nodejs-intelephense
    latex-mode     ; texlab
    kotlin-mode    ; kotlin-language-server
    web-mode)
   . lsp-deferred)
  :config
  (setq lsp-auto-guess-root t)
  (setq lsp-clients-clangd-args '("-j=2"
								  "--background-index"
								  "--clang-tidy"
								  "--compile-commands-dir=build"
								  "--log=error"
								  "--pch-storage=memory"
								  "--enable-config"))
  (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 (concat dot-cache-dir "/lsp-cache"))
  (setq lsp-keep-workspace-alive nil)
  (setq lsp-prefer-flymake nil)
  (setq lsp-session-file (concat dot-cache-dir "/lsp-session-v1"))

  ;; 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))

;; TODO: add lsp-signature keybinds

(use-package lsp-ui
  :commands lsp-ui-mode
  :after (flycheck lsp-mode)
  :config
  (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 Support

Debug Adapter Protocol.

(use-package treemacs
  :after all-the-icons
  :hook (treemacs-mode . dot/hook-disable-line-numbers)
  :config (setq treemacs-persist-file (concat dot-cache-dir "/treemacs/persist")))

(use-package dap-mode
  :after (treemacs lsp-mode)
  :hook (lsp-after-initialize . dot/dap-install-debug-adapters)
  :config
  (setq dap-auto-configure-features '(sessions locals expressions controls tooltip))
  (setq dap-breakpoints-file (concat dot-cache-dir "/dap/breakpoints"))
  (setq dap-utils-extension-path (concat dot-cache-dir "/dap"))

  ;; 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++

(use-package c-mode
  :ensure nil
  :defer t
  ;; C++ // line comment style in c-mode
  :hook (c-mode . (lambda ()
					(c-toggle-comment-style -1))))

CMake

(use-package cmake-mode
  :config (setq cmake-tab-width 4)
  :defer t)

GLSL

(use-package glsl-mode
  :defer t)

HTML

(use-package web-mode
  :defer t)

Kotlin

(use-package kotlin-mode
  :defer t)

Lua

(use-package lua-mode
  :defer t
  :config (setq lua-indent-level 4))

PHP

(use-package php-mode
  :defer t
  :hook
  (php-mode . (lambda ()
				(setq indent-tabs-mode t))))

(use-package restclient
  :defer t)

Python

(use-package python-mode
  :ensure nil
  :defer t
  :hook (python-mode . (lambda ()
						 (setq indent-tabs-mode t)
						 (setq python-indent-offset 4)
						 (setq tab-width 4))))

YAML

(use-package yaml-mode
  :defer t)

Quality of Life

Flycheck

On the fly syntax checking.

(use-package flycheck
  :hook
  ((c-mode-common
	emacs-lisp-mode
	latex-mode
	org-mode
	php-mode
	sh-mode
	shell-mode
	shell-script-mode)
   . flycheck-mode)
  :config
  (setq flycheck-clang-language-standard "c++20")
  (setq flycheck-gcc-language-standard "c++20"))

;; For .el files which are intended to be packages
(use-package flycheck-package
  :after flycheck
  :config
  (add-to-list 'flycheck-checkers 'flycheck-emacs-lisp-package)
  (flycheck-package-setup))

(use-package flycheck-clang-tidy
  :after flycheck
  :hook (flycheck-mode . flycheck-clang-tidy-setup)
  :config (setq flycheck-clang-tidy-extra-options "--format-style=file"))
Flyspell

Give Flyspell a selection menu.

(use-package flyspell-correct
  :after flyspell
  :demand
  :hook (org-mode . flyspell-mode)
  :config
  (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
(use-package rainbow-delimiters
  :hook (prog-mode . rainbow-delimiters-mode))
Rainbow Mode
(use-package rainbow-mode
  :hook (css-mode . rainbow-mode))
YASnippet
(use-package yasnippet
  :defer t
  :init
  (setq yas-snippet-dirs (list (concat dot-emacs-dir "/snippets")))
  (setq yas-prompt-functions '(yas-completing-prompt))
  :config
  (yas-global-mode))

(use-package yasnippet-snippets
  :after yasnippet)

https://stackoverflow.com/questions/22735895/configuring-a-yasnippet-for-two-scenarios-1-region-is-active-2-region-is