commit 02a5e0df28df901418f2745b0201cd813fb307ce Author: Steve Beaulac Date: Sat Feb 28 08:08:35 2026 -0500 init: new dotfile configuration Remove all org files using a new script to more config over, The old org file configuaration were great but required org. This new version only requires the scripts that is included in the repo. The configuration are all done but have not ported the theming system yet. Signed-off-by: Steve Beaulac Change-Id: I14cd7fe058a71c8ba9d6d35397dc8d7e6a6a6964 diff --git a/bootstrap b/bootstrap new file mode 100755 index 0000000..bf793c2 --- /dev/null +++ b/bootstrap @@ -0,0 +1,22 @@ +#!/usr/bin/env bash +set -euo pipefail + +if [[ -z "${DOTFILE_DIR:-}" ]]; then + export DOTFILE_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +fi + +script_dir="$script_dir/installer" + +shopt -s nullglob + +ran_any=false +for script in "$script_dir"/*.sh; do + if [[ -f "$script" && -x "$script" ]]; then + "$script" + ran_any=true + fi +done + +if ! $ran_any; then + echo "No executable .sh scripts found in $script_dir" +fi diff --git a/config/btop/btop.conf b/config/btop/btop.conf new file mode 100644 index 0000000..1f160c5 --- /dev/null +++ b/config/btop/btop.conf @@ -0,0 +1,272 @@ +#? Config file for btop v.1.4.6 + +#* Name of a btop++/bpytop/bashtop formatted ".theme" file, "Default" and "TTY" for builtin themes. +#* Themes should be placed in "../share/btop/themes" relative to binary or "$HOME/.config/btop/themes" +color_theme = "current" + +#* If the theme set background should be shown, set to False if you want terminal background transparency. +theme_background = true + +#* Sets if 24-bit truecolor should be used, will convert 24-bit colors to 256 color (6x6x6 color cube) if false. +truecolor = true + +#* Set to true to force tty mode regardless if a real tty has been detected or not. +#* Will force 16-color mode and TTY theme, set all graph symbols to "tty" and swap out other non tty friendly symbols. +force_tty = false + +#* Define presets for the layout of the boxes. Preset 0 is always all boxes shown with default settings. Max 9 presets. +#* Format: "box_name:P:G,box_name:P:G" P=(0 or 1) for alternate positions, G=graph symbol to use for box. +#* Use whitespace " " as separator between different presets. +#* Example: "cpu:0:default,mem:0:tty,proc:1:default cpu:0:braille,proc:0:tty" +presets = "cpu:1:default,proc:0:default cpu:0:default,mem:0:default,net:0:default cpu:0:block,net:0:tty" + +#* Set to True to enable "h,j,k,l,g,G" keys for directional control in lists. +#* Conflicting keys for h:"help" and k:"kill" is accessible while holding shift. +vim_keys = false + +#* Rounded corners on boxes, is ignored if TTY mode is ON. +rounded_corners = true + +#* Use terminal synchronized output sequences to reduce flickering on supported terminals. +terminal_sync = true + +#* Default symbols to use for graph creation, "braille", "block" or "tty". +#* "braille" offers the highest resolution but might not be included in all fonts. +#* "block" has half the resolution of braille but uses more common characters. +#* "tty" uses only 3 different symbols but will work with most fonts and should work in a real TTY. +#* Note that "tty" only has half the horizontal resolution of the other two, so will show a shorter historical view. +graph_symbol = "braille" + +# Graph symbol to use for graphs in cpu box, "default", "braille", "block" or "tty". +graph_symbol_cpu = "default" + +# Graph symbol to use for graphs in gpu box, "default", "braille", "block" or "tty". +graph_symbol_gpu = "default" + +# Graph symbol to use for graphs in cpu box, "default", "braille", "block" or "tty". +graph_symbol_mem = "default" + +# Graph symbol to use for graphs in cpu box, "default", "braille", "block" or "tty". +graph_symbol_net = "default" + +# Graph symbol to use for graphs in cpu box, "default", "braille", "block" or "tty". +graph_symbol_proc = "default" + +#* Manually set which boxes to show. Available values are "cpu mem net proc" and "gpu0" through "gpu5", separate values with whitespace. +shown_boxes = "cpu mem net proc" + +#* Update time in milliseconds, recommended 2000 ms or above for better sample times for graphs. +update_ms = 2000 + +#* Processes sorting, "pid" "program" "arguments" "threads" "user" "memory" "cpu lazy" "cpu direct", +#* "cpu lazy" sorts top process over time (easier to follow), "cpu direct" updates top process directly. +proc_sorting = "cpu lazy" + +#* Reverse sorting order, True or False. +proc_reversed = false + +#* Show processes as a tree. +proc_tree = false + +#* Use the cpu graph colors in the process list. +proc_colors = true + +#* Use a darkening gradient in the process list. +proc_gradient = true + +#* If process cpu usage should be of the core it's running on or usage of the total available cpu power. +proc_per_core = false + +#* Show process memory as bytes instead of percent. +proc_mem_bytes = true + +#* Show cpu graph for each process. +proc_cpu_graphs = true + +#* Use /proc/[pid]/smaps for memory information in the process info box (very slow but more accurate) +proc_info_smaps = false + +#* Show proc box on left side of screen instead of right. +proc_left = true + +#* (Linux) Filter processes tied to the Linux kernel(similar behavior to htop). +proc_filter_kernel = false + +#* In tree-view, always accumulate child process resources in the parent process. +proc_aggregate = false + +#* Should cpu and memory usage display be preserved for dead processes when paused. +keep_dead_proc_usage = false + +#* Sets the CPU stat shown in upper half of the CPU graph, "total" is always available. +#* Select from a list of detected attributes from the options menu. +cpu_graph_upper = "Auto" + +#* Sets the CPU stat shown in lower half of the CPU graph, "total" is always available. +#* Select from a list of detected attributes from the options menu. +cpu_graph_lower = "Auto" + +#* If gpu info should be shown in the cpu box. Available values = "Auto", "On" and "Off". +show_gpu_info = "Auto" + +#* Toggles if the lower CPU graph should be inverted. +cpu_invert_lower = true + +#* Set to True to completely disable the lower CPU graph. +cpu_single_graph = false + +#* Show cpu box at bottom of screen instead of top. +cpu_bottom = false + +#* Shows the system uptime in the CPU box. +show_uptime = true + +#* Shows the CPU package current power consumption in watts. Requires running `make setcap` or `make setuid` or running with sudo. +show_cpu_watts = true + +#* Show cpu temperature. +check_temp = true + +#* Which sensor to use for cpu temperature, use options menu to select from list of available sensors. +cpu_sensor = "Auto" + +#* Show temperatures for cpu cores also if check_temp is True and sensors has been found. +show_coretemp = true + +#* Set a custom mapping between core and coretemp, can be needed on certain cpus to get correct temperature for correct core. +#* Use lm-sensors or similar to see which cores are reporting temperatures on your machine. +#* Format "x:y" x=core with wrong temp, y=core with correct temp, use space as separator between multiple entries. +#* Example: "4:0 5:1 6:3" +cpu_core_map = "" + +#* Which temperature scale to use, available values: "celsius", "fahrenheit", "kelvin" and "rankine". +temp_scale = "celsius" + +#* Use base 10 for bits/bytes sizes, KB = 1000 instead of KiB = 1024. +base_10_sizes = false + +#* Show CPU frequency. +show_cpu_freq = true + +#* How to calculate CPU frequency, available values: "first", "range", "lowest", "highest" and "average". +freq_mode = "first" + +#* Draw a clock at top of screen, formatting according to strftime, empty string to disable. +#* Special formatting: /host = hostname | /user = username | /uptime = system uptime +clock_format = "%X" + +#* Update main ui in background when menus are showing, set this to false if the menus is flickering too much for comfort. +background_update = true + +#* Custom cpu model name, empty string to disable. +custom_cpu_name = "" + +#* Optional filter for shown disks, should be full path of a mountpoint, separate multiple values with whitespace " ". +#* Only disks matching the filter will be shown. Prepend exclude= to only show disks not matching the filter. Examples: disk_filter="/boot /home/user", disks_filter="exclude=/boot /home/user" +disks_filter = "" + +#* Show graphs instead of meters for memory values. +mem_graphs = true + +#* Show mem box below net box instead of above. +mem_below_net = false + +#* Count ZFS ARC in cached and available memory. +zfs_arc_cached = true + +#* If swap memory should be shown in memory box. +show_swap = true + +#* Show swap as a disk, ignores show_swap value above, inserts itself after first disk. +swap_disk = true + +#* If mem box should be split to also show disks info. +show_disks = true + +#* Filter out non physical disks. Set this to False to include network disks, RAM disks and similar. +only_physical = true + +#* Read disks list from /etc/fstab. This also disables only_physical. +use_fstab = true + +#* Setting this to True will hide all datasets, and only show ZFS pools. (IO stats will be calculated per-pool) +zfs_hide_datasets = false + +#* Set to true to show available disk space for privileged users. +disk_free_priv = false + +#* Toggles if io activity % (disk busy time) should be shown in regular disk usage view. +show_io_stat = true + +#* Toggles io mode for disks, showing big graphs for disk read/write speeds. +io_mode = false + +#* Set to True to show combined read/write io graphs in io mode. +io_graph_combined = false + +#* Set the top speed for the io graphs in MiB/s (100 by default), use format "mountpoint:speed" separate disks with whitespace " ". +#* Example: "/mnt/media:100 /:20 /boot:1". +io_graph_speeds = "" + +#* Set fixed values for network graphs in Mebibits. Is only used if net_auto is also set to False. +net_download = 100 + +net_upload = 100 + +#* Use network graphs auto rescaling mode, ignores any values set above and rescales down to 10 Kibibytes at the lowest. +net_auto = true + +#* Sync the auto scaling for download and upload to whichever currently has the highest scale. +net_sync = true + +#* Starts with the Network Interface specified here. +net_iface = "" + +#* "True" shows bitrates in base 10 (Kbps, Mbps). "False" shows bitrates in binary sizes (Kibps, Mibps, etc.). "Auto" uses base_10_sizes. +base_10_bitrate = "Auto" + +#* Show battery stats in top right if battery is present. +show_battery = true + +#* Which battery to use if multiple are present. "Auto" for auto detection. +selected_battery = "Auto" + +#* Show power stats of battery next to charge indicator. +show_battery_watts = true + +#* Set loglevel for "~/.local/state/btop.log" levels are: "ERROR" "WARNING" "INFO" "DEBUG". +#* The level set includes all lower levels, i.e. "DEBUG" will show all logging info. +log_level = "WARNING" + +#* Automatically save current settings to config file on exit. +save_config_on_exit = true + +#* Measure PCIe throughput on NVIDIA cards, may impact performance on certain cards. +nvml_measure_pcie_speeds = true + +#* Measure PCIe throughput on AMD cards, may impact performance on certain cards. +rsmi_measure_pcie_speeds = true + +#* Horizontally mirror the GPU graph. +gpu_mirror_graph = true + +#* Set which GPU vendors to show. Available values are "nvidia amd intel" +shown_gpus = "nvidia amd intel" + +#* Custom gpu0 model name, empty string to disable. +custom_gpu_name0 = "" + +#* Custom gpu1 model name, empty string to disable. +custom_gpu_name1 = "" + +#* Custom gpu2 model name, empty string to disable. +custom_gpu_name2 = "" + +#* Custom gpu3 model name, empty string to disable. +custom_gpu_name3 = "" + +#* Custom gpu4 model name, empty string to disable. +custom_gpu_name4 = "" + +#* Custom gpu5 model name, empty string to disable. +custom_gpu_name5 = "" diff --git a/config/chromium-flags.conf b/config/chromium-flags.conf new file mode 100644 index 0000000..5b3eac5 --- /dev/null +++ b/config/chromium-flags.conf @@ -0,0 +1,4 @@ +--ozone-platform=wayland +--ozone-platform-hint=wayland +--enable-features=TouchpadOverscrollHistoryNavigation +--disable-features=WaylandWpColorManagerV1 diff --git a/config/emacs/early-init.el b/config/emacs/early-init.el new file mode 100644 index 0000000..5fd6401 --- /dev/null +++ b/config/emacs/early-init.el @@ -0,0 +1,312 @@ +;;; early-init.el --- Early Init -*- no-byte-compile: t; lexical-binding: t; -*- + +;; Author: James Cherti +;; URL: https://github.com/jamescherti/minimal-emacs.d +;; Package-Requires: ((emacs "29.1")) +;; Keywords: maint +;; Version: 1.1.0 +;; SPDX-License-Identifier: GPL-3.0-or-later + +;;; Commentary: +;; The minimal-emacs.d starter kit provides improved Emacs defaults and +;; optimized startup, intended to serve as a solid foundation for your vanilla +;; Emacs configuration and enhance your overall Emacs experience. + +;;; Code: + +;;; Variables + +(defvar minimal-emacs-ui-features '() + "List of user interface features to disable in minimal Emacs setup. + +This variable holds a list Emacs UI features that can be enabled: +- `context-menu`: Enables the context menu in graphical environments. +- `tool-bar`: Enables the tool bar in graphical environments. +- `menu-bar`: Enables the menu bar in graphical environments. +- `dialogs`: Enables both file dialogs and dialog boxes. +- `tooltips`: Enables tooltips. + +Each feature in the list corresponds to a specific UI component that can be +turned on.") + +(defvar minimal-emacs-frame-title-format "%b – Emacs" + "Template for displaying the title bar of visible and iconified frame.") + +(defvar minimal-emacs-debug nil + "Non-nil to enable debug.") + +(defvar minimal-emacs-gc-cons-threshold (* 16 1024 1024) + "The value of `gc-cons-threshold' after Emacs startup.") + +(defvar minimal-emacs-package-initialize-and-refresh t + "Whether to automatically initialize and refresh packages. +When set to non-nil, Emacs will automatically call `package-initialize' and +`package-refresh-contents' to set up and update the package system.") + +(defvar minimal-emacs-user-directory user-emacs-directory + "The default value of the `user-emacs-directory' variable.") + +;;; Load pre-early-init.el + +(defun minimal-emacs-load-user-init (filename) + "Execute a file of Lisp code named FILENAME." + (let ((user-init-file + (expand-file-name filename + minimal-emacs-user-directory))) + (when (file-exists-p user-init-file) + (load user-init-file nil t)))) + +(minimal-emacs-load-user-init "pre-early-init.el") + +(setq custom-theme-directory + (expand-file-name "themes/" minimal-emacs-user-directory)) +(setq custom-file (expand-file-name "custom.el" minimal-emacs-user-directory)) + +;;; Misc + +(set-language-environment "UTF-8") + +;; Set-language-environment sets default-input-method, which is unwanted. +(setq default-input-method nil) + +;; Some features that are not represented as packages can be found in +;; `features', but this can be inconsistent. The following enforce consistency: +(if (fboundp #'json-parse-string) + (push 'jansson features)) +(if (string-match-p "HARFBUZZ" system-configuration-features) ; no alternative + (push 'harfbuzz features)) +(if (bound-and-true-p module-file-suffix) + (push 'dynamic-modules features)) + +;;; Garbage collection +;; Garbage collection significantly affects startup times. This setting delays +;; garbage collection during startup but will be reset later. + +(setq gc-cons-threshold most-positive-fixnum) + +(add-hook 'emacs-startup-hook + (lambda () + (setq gc-cons-threshold minimal-emacs-gc-cons-threshold))) + +;;; Performance + +;; Prefer loading newer compiled files +(setq load-prefer-newer t) + +;; Increase how much is read from processes in a single chunk (default is 4kb). +(setq read-process-output-max (* 512 1024)) ; 512kb + +;; Reduce rendering/line scan work by not rendering cursors or regions in +;; non-focused windows. +(setq-default cursor-in-non-selected-windows nil) +(setq highlight-nonselected-windows nil) + +;; Disable warnings from the legacy advice API. They aren't useful. +(setq ad-redefinition-action 'accept) + +(setq warning-suppress-types '((lexical-binding))) + +;; Don't ping things that look like domain names. +(setq ffap-machine-p-known 'reject) + +;; By default, Emacs "updates" its ui more often than it needs to +(setq idle-update-delay 1.0) + +;; Font compacting can be very resource-intensive, especially when rendering +;; icon fonts on Windows. This will increase memory usage. +(setq inhibit-compacting-font-caches t) + +(unless (daemonp) + (let ((old-value (default-toplevel-value 'file-name-handler-alist))) + (set-default-toplevel-value + 'file-name-handler-alist + ;; Determine the state of bundled libraries using calc-loaddefs.el. + ;; If compressed, retain the gzip handler in `file-name-handler-alist`. + ;; If compiled or neither, omit the gzip handler during startup for + ;; improved startup and package load time. + (if (eval-when-compile + (locate-file-internal "calc-loaddefs.el" load-path)) + nil + (list (rassq 'jka-compr-handler old-value)))) + ;; Ensure the new value persists through any current let-binding. + (set-default-toplevel-value 'file-name-handler-alist + file-name-handler-alist) + ;; Remember the old value to reset it as needed. + (add-hook 'emacs-startup-hook + (lambda () + (set-default-toplevel-value + 'file-name-handler-alist + ;; Merge instead of overwrite to preserve any changes made + ;; since startup. + (delete-dups (append file-name-handler-alist old-value)))) + 101)) + + (unless noninteractive + (progn + ;; Disable mode-line-format during init + (defun minimal-emacs--reset-inhibited-vars-h () + (setq-default inhibit-redisplay nil + ;; Inhibiting `message' only prevents redraws and + inhibit-message nil) + (redraw-frame)) + + (defvar minimal-emacs--default-mode-line-format mode-line-format + "Default value of `mode-line-format'.") + (setq-default mode-line-format nil) + + (defun minimal-emacs--startup-load-user-init-file (fn &rest args) + "Advice for startup--load-user-init-file to reset mode-line-format." + (let (init) + (unwind-protect + (progn + (apply fn args) ; Start up as normal + (setq init t)) + (unless init + ;; If we don't undo inhibit-{message, redisplay} and there's an + ;; error, we'll see nothing but a blank Emacs frame. + (minimal-emacs--reset-inhibited-vars-h)) + (unless (default-toplevel-value 'mode-line-format) + (setq-default mode-line-format + minimal-emacs--default-mode-line-format))))) + + (advice-add 'startup--load-user-init-file :around + #'minimal-emacs--startup-load-user-init-file)) + + ;; Without this, Emacs will try to resize itself to a specific column size + (setq frame-inhibit-implied-resize t) + + ;; A second, case-insensitive pass over `auto-mode-alist' is time wasted. + ;; No second pass of case-insensitive search over auto-mode-alist. + (setq auto-mode-case-fold nil) + + ;; Reduce *Message* noise at startup. An empty scratch buffer (or the + ;; dashboard) is more than enough, and faster to display. + (setq inhibit-startup-screen t + inhibit-startup-echo-area-message user-login-name) + (setq initial-buffer-choice nil + inhibit-startup-buffer-menu t + inhibit-x-resources t) + + ;; Disable bidirectional text scanning for a modest performance boost. + (setq-default bidi-display-reordering 'left-to-right + bidi-paragraph-direction 'left-to-right) + + ;; Give up some bidirectional functionality for slightly faster re-display. + (setq bidi-inhibit-bpa t) + + ;; Remove "For information about GNU Emacs..." message at startup + (advice-add #'display-startup-echo-area-message :override #'ignore) + + ;; Suppress the vanilla startup screen completely. We've disabled it with + ;; `inhibit-startup-screen', but it would still initialize anyway. + (advice-add #'display-startup-screen :override #'ignore) + + ;; Shave seconds off startup time by starting the scratch buffer in + ;; `fundamental-mode' + (setq initial-major-mode 'fundamental-mode + initial-scratch-message nil) + + (unless minimal-emacs-debug + ;; Unset command line options irrelevant to the current OS. These options + ;; are still processed by `command-line-1` but have no effect. + (unless (eq system-type 'darwin) + (setq command-line-ns-option-alist nil)) + (unless (memq initial-window-system '(x pgtk)) + (setq command-line-x-option-alist nil))))) + +;;; Native compilation and Byte compilation + +(if (and (featurep 'native-compile) + (fboundp 'native-comp-available-p) + (native-comp-available-p)) + ;; Activate `native-compile' + (setq native-comp-jit-compilation t + native-comp-deferred-compilation t ; Obsolete since Emacs 29.1 + package-native-compile t) + ;; Deactivate the `native-compile' feature if it is not available + (setq features (delq 'native-compile features))) + +;; Suppress compiler warnings and don't inundate users with their popups. +(setq native-comp-async-report-warnings-errors + (or minimal-emacs-debug 'silent)) +(setq native-comp-warning-on-missing-source minimal-emacs-debug) + +(setq debug-on-error minimal-emacs-debug + jka-compr-verbose minimal-emacs-debug) + +(setq byte-compile-warnings minimal-emacs-debug) +(setq byte-compile-verbose minimal-emacs-debug) + +;;; UI elements + +(setq frame-title-format minimal-emacs-frame-title-format + icon-title-format minimal-emacs-frame-title-format) + +;; Disable startup screens and messages +(setq inhibit-splash-screen t) + +;; I intentionally avoid calling `menu-bar-mode', `tool-bar-mode', and +;; `scroll-bar-mode' because manipulating frame parameters can trigger or queue +;; a superfluous and potentially expensive frame redraw at startup, depending +;; on the window system. The variables must also be set to `nil' so users don't +;; have to call the functions twice to re-enable them. +(unless (memq 'menu-bar minimal-emacs-ui-features) + (push '(menu-bar-lines . 0) default-frame-alist) + (unless (memq window-system '(mac ns)) + (setq menu-bar-mode nil))) + +(unless (daemonp) + (unless noninteractive + (when (fboundp 'tool-bar-setup) + ;; Temporarily override the tool-bar-setup function to prevent it from + ;; running during the initial stages of startup + (advice-add #'tool-bar-setup :override #'ignore) + (define-advice startup--load-user-init-file + (:before (&rest _) minimal-emacs-setup-toolbar) + (advice-remove #'tool-bar-setup #'ignore) + (tool-bar-setup))))) +(unless (memq 'tool-bar minimal-emacs-ui-features) + (push '(tool-bar-lines . 0) default-frame-alist) + (setq tool-bar-mode nil)) + +(push '(vertical-scroll-bars) default-frame-alist) +(push '(horizontal-scroll-bars) default-frame-alist) +(setq scroll-bar-mode nil) +(when (fboundp 'horizontal-scroll-bar-mode) + (horizontal-scroll-bar-mode -1)) + +(unless (memq 'tooltips minimal-emacs-ui-features) + (when (bound-and-true-p tooltip-mode) + (tooltip-mode -1))) + +;; Disable GUIs because they are inconsistent across systems, desktop +;; environments, and themes, and they don't match the look of Emacs. +(unless (memq 'dialogs minimal-emacs-ui-features) + (setq use-file-dialog nil) + (setq use-dialog-box nil)) + +;; Allow for shorter responses: "y" for yes and "n" for no. +(if (boundp 'use-short-answers) + (setq use-short-answers t) + (advice-add #'yes-or-no-p :override #'y-or-n-p)) +(defalias #'view-hello-file #'ignore) ; Never show the hello file + +;;; package.el +(setq package-enable-at-startup nil) +(setq package-quickstart nil) +(setq use-package-always-ensure t) +(setq package-archives '(("melpa" . "https://melpa.org/packages/") + ("melpa-stable" . "https://stable.melpa.org/packages/") + ("gnu" . "https://elpa.gnu.org/packages/") + ("nongnu" . "https://elpa.nongnu.org/nongnu/"))) +(customize-set-variable 'package-archive-priorities '(("gnu" . 99) + ("nongnu" . 80) + ("stable" . 70) + ("melpa" . 0))) + +;;; Load post-early-init.el +(minimal-emacs-load-user-init "post-early-init.el") + +(provide 'early-init) + +;;; early-init.el ends here \ No newline at end of file diff --git a/config/emacs/init.el b/config/emacs/init.el new file mode 100644 index 0000000..8295861 --- /dev/null +++ b/config/emacs/init.el @@ -0,0 +1,356 @@ +;;; init.el --- Init -*- no-byte-compile: t; lexical-binding: t; -*- + +;; Author: James Cherti +;; URL: https://github.com/jamescherti/minimal-emacs.d +;; Package-Requires: ((emacs "29.1")) +;; Keywords: maint +;; Version: 1.1.0 +;; SPDX-License-Identifier: GPL-3.0-or-later + +;;; Commentary: +;; The minimal-emacs.d starter kit provides improved Emacs defaults and +;; optimized startup, intended to serve as a solid foundation for your vanilla +;; Emacs configuration and enhance your overall Emacs experience. + +;;; Code: + +;;; Load pre-init.el +(minimal-emacs-load-user-init "pre-init.el") + +;;; package.el +(when (bound-and-true-p minimal-emacs-package-initialize-and-refresh) + ;; Initialize and refresh package contents again if needed + (package-initialize) + (unless package-archive-contents + (package-refresh-contents)) + + ;; Install use-package if necessary + (unless (package-installed-p 'use-package) + (package-install 'use-package)) + + ;; Ensure use-package is available at compile time + (eval-when-compile + (require 'use-package))) + +;; Ensure the 'use-package' package is installed and loaded + +;;; Minibuffer +;; Allow nested minibuffers +(setq enable-recursive-minibuffers t) + +;; Keep the cursor out of the read-only portions of the.minibuffer +(setq minibuffer-prompt-properties + '(read-only t intangible t cursor-intangible t face + minibuffer-prompt)) +(add-hook 'minibuffer-setup-hook #'cursor-intangible-mode) + +;;; Misc + +;; switch-to-buffer runs pop-to-buffer-same-window instead +(setq switch-to-buffer-obey-display-actions t) + +(setq show-paren-delay 0.1 + show-paren-highlight-openparen t + show-paren-when-point-inside-paren t + show-paren-when-point-in-periphery t) + +(setq whitespace-line-column nil) ; whitespace-mode + +;; I reduced the default value of 9 to simplify the font-lock keyword, +;; aiming to improve performance. This package helps differentiate +;; nested delimiter pairs, particularly in languages with heavy use of +;; parentheses. +(setq rainbow-delimiters-max-face-count 5) + +;; Can be activated with `display-line-numbers-mode' +(setq-default display-line-numbers-width 3) +(setq-default display-line-numbers-widen t) + +(setq comint-prompt-read-only t) +(setq comint-buffer-maximum-size 2048) + +(setq compilation-always-kill t + compilation-ask-about-save nil + compilation-scroll-output 'first-error) + +(setq truncate-string-ellipsis "…") + +;; Configure Emacs to ask for confirmation before exiting +(setq confirm-kill-emacs 'y-or-n-p) + +;; Delete by moving to trash in interactive mode +(setq delete-by-moving-to-trash (not noninteractive)) + +;;; Files + +;; Disable the warning "X and Y are the same file". Ignoring this warning is +;; acceptable since it will redirect you to the existing buffer regardless. +(setq find-file-suppress-same-file-warnings t) + +;; Resolve symlinks when opening files, so that any operations are conducted +;; from the file's true directory (like `find-file'). +(setq find-file-visit-truename t + vc-follow-symlinks t) + +;; Skip confirmation prompts when creating a new file or buffer +(setq confirm-nonexistent-file-or-buffer nil) + +(setq uniquify-buffer-name-style 'forward) + +(setq mouse-yank-at-point t) + +;; Prefer vertical splits over horizontal ones +(setq split-width-threshold 170 + split-height-threshold nil) + +;; The native border "uses" a pixel of the fringe on the rightmost +;; splits, whereas `window-divider` does not. +(setq window-divider-default-bottom-width 1 + window-divider-default-places t + window-divider-default-right-width 1) + +(add-hook 'after-init-hook #'window-divider-mode) + +;;; Backup files + +;; Avoid generating backups or lockfiles to prevent creating world-readable +;; copies of files. +(setq create-lockfiles nil) +(setq make-backup-files nil) + +(setq backup-directory-alist + `(("." . ,(expand-file-name "backup" user-emacs-directory)))) +(setq tramp-backup-directory-alist backup-directory-alist) +(setq backup-by-copying-when-linked t) +(setq backup-by-copying t) ; Backup by copying rather renaming +(setq delete-old-versions t) ; Delete excess backup versions silently +(setq version-control t) ; Use version numbers for backup files +(setq kept-new-versions 5) +(setq kept-old-versions 5) +(setq vc-make-backup-files nil) ; Do not backup version controlled files + +;;; Auto save +;; Enable auto-save to safeguard against crashes or data loss. The +;; `recover-file' or `recover-session' functions can be used to restore +;; auto-saved data. +(setq auto-save-default t) + +;; Do not auto-disable auto-save after deleting large chunks of +;; text. The purpose of auto-save is to provide a failsafe, and +;; disabling it contradicts this objective. +(setq auto-save-include-big-deletions t) + +(setq auto-save-list-file-prefix + (expand-file-name "autosave/" user-emacs-directory)) +(setq tramp-auto-save-directory + (expand-file-name "tramp-autosave/" user-emacs-directory)) + +;; Auto save options +(setq kill-buffer-delete-auto-save-files t) + +;;; Auto revert +;; Auto-revert in Emacs is a feature that automatically updates the +;; contents of a buffer to reflect changes made to the underlying file +;; on disk. +(setq revert-without-query (list ".") ; Do not prompt + auto-revert-stop-on-user-input nil + auto-revert-verbose t) + +;; Revert other buffers (e.g, Dired) +(setq global-auto-revert-non-file-buffers t) + +;;; recentf +;; `recentf' is an Emacs package that maintains a list of recently +;; accessed files, making it easier to reopen files you have worked on +;; recently. +(setq recentf-max-saved-items 300) ; default is 20 +(setq recentf-auto-cleanup 'mode) + +;;; saveplace +;; `save-place-mode` enables Emacs to remember the last location within a file +;; upon reopening. This feature is particularly beneficial for resuming work at +;; the precise point where you previously left off. +(setq save-place-file (expand-file-name "saveplace" user-emacs-directory)) +(setq save-place-limit 600) + +;;; savehist +;; `savehist` is an Emacs feature that preserves the minibuffer history between +;; sessions. It saves the history of inputs in the minibuffer, such as commands, +;; search strings, and other prompts, to a file. This allows users to retain +;; their minibuffer history across Emacs restarts. +(setq history-length 300) +(setq savehist-save-minibuffer-history t) ;; Default + +;;; Frames and windows + +;; Resizing the Emacs frame can be costly when changing the font. Disable this +;; to improve startup times with fonts larger than the system default. +(setq frame-resize-pixelwise t) + +;; However, do not resize windows pixelwise, as this can cause crashes in some +;; cases when resizing too many windows at once or rapidly. +(setq window-resize-pixelwise nil) + +(setq resize-mini-windows 'grow-only) + +;;; Scrolling +;; Enables faster scrolling through unfontified regions. This may result in +;; brief periods of inaccurate syntax highlighting immediately after scrolling, +;; which should quickly self-correct. +(setq fast-but-imprecise-scrolling t) + +;; Move point to top/bottom of buffer before signaling a scrolling error. +(setq scroll-error-top-bottom t) + +;; Keeps screen position if the scroll command moved it vertically out of the +;; window. +(setq scroll-preserve-screen-position t) + +;;; Mouse + +;; Emacs 29 +(when (memq 'context-menu minimal-emacs-ui-features) + (when (and (display-graphic-p) (fboundp 'context-menu-mode)) + (add-hook 'after-init-hook #'context-menu-mode))) + +(setq hscroll-margin 2 + hscroll-step 1 + ;; Emacs spends excessive time recentering the screen when the cursor + ;; moves more than N lines past the window edges (where N is the value of + ;; `scroll-conservatively`). This can be particularly slow in larger files + ;; during extensive scrolling. If `scroll-conservatively` is set above + ;; 100, the window is never automatically recentered. The default value of + ;; 0 triggers recentering too aggressively. Setting it to 10 reduces + ;; excessive recentering and only recenters the window when scrolling + ;; significantly off-screen. + scroll-conservatively 10 + scroll-margin 0 + scroll-preserve-screen-position t + ;; Reduce cursor lag by preventing automatic adjustments to + ;; `window-vscroll' for unusually long lines. Setting + ;; `auto-window-vscroll' it to nil also resolves the issue of random + ;; half-screen jumps during scrolling. + auto-window-vscroll nil + ;; Mouse + mouse-wheel-scroll-amount '(1 ((shift) . hscroll)) + mouse-wheel-scroll-amount-horizontal 1) + +;;; Cursor +;; The blinking cursor is distracting and interferes with cursor settings in +;; some minor modes that try to change it buffer-locally (e.g., Treemacs). +;; Additionally, it can cause freezing, especially on macOS, for users with +;; customized and colored cursors. +(blink-cursor-mode -1) + +;; Don't blink the paren matching the one at point, it's too distracting. +(setq blink-matching-paren nil) + +;; Don't stretch the cursor to fit wide characters, it is disorienting, +;; especially for tabs. +(setq x-stretch-cursor nil) + +;;; Annoyances + +;; No beeping or blinking +(setq visible-bell nil) +(setq ring-bell-function #'ignore) + +;; This controls how long Emacs will blink to show the deleted pairs with +;; `delete-pair'. A longer delay can be annoying as it causes a noticeable pause +;; after each deletion, disrupting the flow of editing. +(setq delete-pair-blink-delay 0.03) + +;;; Indent and formatting +(setq-default left-fringe-width 8) +(setq-default right-fringe-width 8) + +;; Do not show an arrow at the top/bottomin the fringe and empty lines +(setq-default indicate-buffer-boundaries nil) +(setq-default indicate-empty-lines nil) + +;; Continue wrapped lines at whitespace rather than breaking in the +;; middle of a word. +(setq-default word-wrap t) + +;; Disable wrapping by default due to its performance cost. +(setq-default truncate-lines t) + +;; If enabled and `truncate-lines' is disabled, soft wrapping will not occur +;; when the window is narrower than `truncate-partial-width-windows' characters. +(setq truncate-partial-width-windows nil) + +;; Prefer spaces over tabs. Spaces offer a more consistent default compared to +;; 8-space tabs. This setting can be adjusted on a per-mode basis as needed. +(setq-default indent-tabs-mode nil + tab-width 4) + +;; Enable indentation and completion using the TAB key +(setq-default tab-always-indent nil) + +;; Enable multi-line commenting which ensures that `comment-indent-new-line' +;; properly continues comments onto new lines, which is useful for writing +;; longer comments or docstrings that span multiple lines. +(setq comment-multi-line t) + +;; We often split terminals and editor windows or place them side-by-side, +;; making use of the additional horizontal space. +(setq-default fill-column 80) + +;; Disable the obsolete practice of end-of-line spacing from the +;; typewriter era. +(setq sentence-end-double-space nil) + +;; According to the POSIX, a line is defined as "a sequence of zero or +;; more non-newline characters followed by a terminating newline". +(setq require-final-newline t) + +;; Remove duplicates from the kill ring to reduce clutter +(setq kill-do-not-save-duplicates t) + +;; Ensures that empty lines within the commented region are also commented out. +;; This prevents unintended visual gaps and maintains a consistent appearance, +;; ensuring that comments apply uniformly to all lines, including those that are +;; otherwise empty. +(setq comment-empty-lines t) + +;; Eliminate delay before highlighting search matches +(setq lazy-highlight-initial-delay 0) + +;;; Mode line + +;; Setting `display-time-default-load-average' to nil makes Emacs omit the load +;; average information from the mode line. +(setq display-time-default-load-average nil) + +;; Display the current line and column numbers in the mode line +(setq line-number-mode t) +(setq column-number-mode t) + +;;; Filetype + +;; Do not notify the user each time Python tries to guess the indentation offset +(setq python-indent-guess-indent-offset-verbose nil) + +(setq sh-indent-after-continuation 'always) + +(setq dired-clean-confirm-killing-deleted-buffers nil + dired-recursive-deletes 'top + dired-recursive-copies 'always + dired-create-destination-dirs 'ask) + +;;; Font / Text scale + +;; Avoid automatic frame resizing when adjusting settings. +(setq global-text-scale-adjust-resizes-frames nil) + +;;; Ediff + +;; Configure Ediff to use a single frame and split windows horizontally +(setq ediff-window-setup-function #'ediff-setup-windows-plain + ediff-split-window-function #'split-window-horizontally) + +;;; Load post-init.el +(minimal-emacs-load-user-init "post-init.el") + +(provide 'init) +;;; init.el ends here \ No newline at end of file diff --git a/config/emacs/org-roam-templates/default.org b/config/emacs/org-roam-templates/default.org new file mode 100644 index 0000000..b6b2b16 --- /dev/null +++ b/config/emacs/org-roam-templates/default.org @@ -0,0 +1,7 @@ +,#+TITLE: ${title} +,#+AUTHOR: Steve Beaulac +,#+OPTIONS: title:nil toc:nil +,#+EXPORT_FILE_NAME: /tmp/ +,#+LaTex_CLASS: short +,#+LATEX_HEADER: \runningtitle{Shortened Title} +,#+LATEX_HEADER: wordcount{36} \ No newline at end of file diff --git a/config/emacs/post-early-init.el b/config/emacs/post-early-init.el new file mode 100644 index 0000000..ae8b5b5 --- /dev/null +++ b/config/emacs/post-early-init.el @@ -0,0 +1,55 @@ +;;;; post-early-init.el --- Early Init -*- no-byte-compile: t; lexical-binding: t; -*- +;; Compile warnings + +(setq warning-minimum-level :emergency) +(setq warning-minimum-log-level :emergency) +(setq gc-cons-percentage 0.6) + +;; Revert Dired and other buffers +(customize-set-variable 'global-auto-revert-non-file-buffers t) + +;; Revert buffers when the underlying file has changed +(add-hook 'after-init-hooks #'global-auto-revert-mode) +(setq auto-revert-interval 1) + +(setq-default default-frame-alist '((undecorated . t))) + +(setq process-adaptive-read-buffering nil) + +(add-hook 'focus-out-hook #'garbage-collect) +;(add-hook 'after-save-hook #'garbage-collect) +;(run-with-idle-timer 5 t (lambda () (garbage-collect))) + +(setq-default ispell-program-name "aspell") +(setq-default ispell-local-dictionary "english") + +(when (fboundp 'set-scroll-bar-mode) + (set-scroll-bar-mode nil)) + +(when (fboundp 'pixel-scroll-precision-mode) + (setq pixel-scroll-precision-large-scroll-height 40.0) + (pixel-scroll-precision-mode 1)) + +(when (fboundp 'pixel-scroll-mode) + (pixel-scroll-mode 1)) + +(setq tramp-default-host "localhost") + +;; disable startup messages +(setq inhibit-startup-message t) + +(setq large-file-warning-threshold nil) + +;;; package.el +;;(setq use-package-expand-minimally t) +;;(setq package-install-upgrade-built-in t) +;;(setq use-package-enable-imenu-support t) + +(when init-file-debug + (setq use-package-verbose t + use-package-debug t + use-package-expand-minimally nil + use-package-compute-statistics t + debug-on-error t)) + +(provide 'post-early-init) \ No newline at end of file diff --git a/config/emacs/post-init.el b/config/emacs/post-init.el new file mode 100644 index 0000000..862b061 --- /dev/null +++ b/config/emacs/post-init.el @@ -0,0 +1,4602 @@ +;;;; post-init.el --- Init -*- no-byte-compile: t; lexical-binding: t; -*- + +(add-to-list 'exec-path "~/.local/bin") +(add-to-list 'exec-path "~/bin") + +(setq tls-checktrust t) +(setq gnutls-verify-error t) + +(setq tab-always-indent 'complete) + +(setq completion-cycle-threshold 3) ; Always show candidates in menu-bar-lines + +(keymap-global-set " " #'ibuffer-list-buffers) + +;;(setq-default search-whitespace-regexp ".*") + +(delete-selection-mode t) ; make typing override text selection +(setq bookmark-save-flag t + case-fold-search t + clean-buffer-list-delay-general t + dabrev-case-fold-search t + file-name-shadow-mode 1 + help-window-select t + ns-use-native-fullscreen nil + save-abbrevs 'silent + save-interprogram-paste-before-kill t + select-active-regions t + set-mark-command-repeat-pop t + tooltip-delay 1.5 + tooltip-use-echo-area t + view-read-only t) + +;; (electric-indent-mode -1) + +;;(setq next-error-message-highlight t) +;;(setq recenter-positions '(top middle bottom)) +;;(setq visual-line-fringe-indicators '(left-curly-arrow right-curly-arrow)) + +(setq tab-bar-show nil) + +(auto-compression-mode t) +(global-subword-mode t) +(global-so-long-mode t) +(global-hl-line-mode -1) + +(setq display-line-numbers-type 'relative) + +(setq display-line-numbers-grow-only t) +(global-display-line-numbers-mode 1) + +(when (fboundp 'winner-mode) + (winner-mode 1)) + +;; show line numbers on the left side of a window +(pending-delete-mode t) +;;(toggle-save-place-globally 1) +(transient-mark-mode t) + +(setq password-cache t + password-cache-expiry 3600) + +(setq mode-require-final-newline 'visit-save) + +(defvar sys-tools "/opt") +(if (eq system-type 'windows-nt) + (setq sys-tools "c:\\utils")) + +(setq auth-sources + '((:source "~/.emacs.d/.authinfo.gpg"))) + +(require 'semantic/db-file) + +(setq custom-file null-device) + +;; TODO (advice-add 'jsonrpc--log-event :override #'ignore) +(add-hook 'before-save-hook 'whitespace-cleanup) + +(use-package diminish + :ensure t + :config + (diminish 'lisp-interaction-mode " iElisp") + (diminish 'emacs-lisp-mode " Εlisp") + (diminish 'word-wrap-mode "Щ") + (diminish 'eldoc-mode)) + +(use-package general :ensure t) + +(use-package which-key + :ensure t + :demand t + :diminish + :custom + (which-key-sort-order 'which-key-prefix-then-key-order) + (which-key-add-column-padding 2) + (which-key-popup-type 'side-window) + (which-key-max-display-columns nil) + (which-key-separator " ") + :config + (which-key-mode) + (which-key-setup-minibuffer)) + +(use-package xdg + :ensure nil + :config + (let ((backup-dir (expand-file-name "emacs/backup/" (xdg-data-home))) + (autosave-dir (expand-file-name "emacs/autosave/" (xdg-cache-home)))) + (mkdir backup-dir t) + (mkdir autosave-dir t) + + (setq backup-directory-alist + `(("." . ,backup-dir))) + + (setq tramp-backup-directory-alist backup-directory-alist) + (setq auto-save-file-name-transforms + `((".*" ,autosave-dir t)))) + + (setq tramp-auto-save-directory + (expand-file-name "tramp-autosave/" (xdg-cache-home))) + + ;;(setq custom-file (expand-file-name "emacs/custom.el" (xdg-data-home))) + (setq auto-save-list-file-prefix (expand-file-name "emacs/auto-save-list/.saves-" (xdg-cache-home))) + (setq url-history-file (expand-file-name "emacs/url/history" (xdg-data-home))) + (setq save-place-file (expand-file-name "saveplace" (xdg-data-home)))) + +;;(setq-default line-spacing 0.12) +;(set-face-attribute 'default nil :family "0xProto" :height 130) +;(set-face-attribute 'fixed-pitch nil :family "0xProto" :height 130) +;(set-face-attribute 'fixed-pitch-serif nil :family "0xProto" :height 130) +;(set-face-attribute 'variable-pitch nil :family "0xProto" :height 130) + +(set-face-attribute 'default nil :family "MonaspiceNe Nerd Font Mono" :height 130) +(set-face-attribute 'variable-pitch nil :family "MonaspiceRn Nerd Font Propo" :height 130) +(set-face-attribute 'fixed-pitch nil :family "MonaspiceAr Nerd Font Propo" :height 130) +(set-face-attribute 'fixed-pitch-serif nil :family "MonaspiceXe Nerd Font" :height 130) + +;;(set-face-attribute 'variable-pitch nil :family "Monaspace Radon" :height 130) +;;(set-face-attribute 'fixed-pitch nil :family "Monaspace Argon" :height 130) +;;(set-face-attribute 'fixed-pitch-serif nil :family "Monaspace Xenon" :height 130) + +(use-package mixed-pitch + :after org + :hook + (org-mode . mixed-pitch-mode)) + +(use-package all-the-icons + :ensure t + :defer t + :config + (defun unpackaged/disable-all-the-icons () + "Disable all-the-icons." + (all-the-icons-dired-mode 0)) + + (defun unpackaged/restore-all-the-icons () + "Restore all-the-icons." + (all-the-icons-dired-mode 1)) + + (advice-add 'wdired-change-to-wdired-mode + :before #'unpackaged/disable-all-the-icons) + (advice-add 'wdired-finish-edit + :after #'unpackaged/restore-all-the-icons) + (advice-add 'wdired-abort-changes + :after #'unpackaged/restore-all-the-icons)) + +(use-package all-the-icons-completion + :after (marginalia all-the-icons) + :hook (marginalia-mode . all-the-icons-completion-marginalia-setup) + :init + (all-the-icons-completion-mode)) + +(use-package all-the-icons-nerd-fonts + :after all-the-icons + :config + (all-the-icons-nerd-fonts-prefer)) + +(use-package telephone-line + :demand t + :ensure t + :config + (setq telephone-line-primary-left-separator 'telephone-line-gradient + telephone-line-secondary-left-separator 'telephone-line-nil + telephone-line-primary-right-separator 'telephone-line-gradient + telephone-line-secondary-right-separator 'telephone-line-nil) + (setq telephone-line-height 28 + telephone-line-evil-use-short-tag t) + + (setq telephone-line-lhs + '((evil . (telephone-line-evil-tag-segment)) + (accent . (telephone-line-major-mode-segment + telephone-line-process-segment)) + (nil . (telephone-line-project-segment)) + (nil . (telephone-line-buffer-segment)))) + + (setq telephone-line-rhs + '((nil . (telephone-line-flymake-segment + telephone-line-misc-info-segment)) + (evil . (telephone-line-vc-segment )))) + + (telephone-line-mode t)) + +(use-package modus-themes + :ensure t + :defer t + :config + (setq modus-themes-italic-constructs t + modus-themes-bold-constructs t + modus-themes-mixed-fonts t + modus-themes-subtle-line-numbers nil + modus-themes-deuteranopia t + modus-themes-tabs-accented nil + modus-themes-variable-pitch-ui t + modus-themes-inhibit-reload t) + + (setq modus-themes-fringes 'intense) + (setq modus-themes-lang-checkers '(straight-underline text-also)) + ;(setq modus-themes-mode-line '(borderless (padding . 4) (height . 1.1))) + (setq modus-themes-markup '(background italic intense)) + (setq modus-themes-syntax '(yellow-comments green-strings alt-syntax)) + (setq modus-themes-hl-line '(accented)) + (setq modus-themes-paren-match '(bold intense)) + + (setq modus-themes-links '(neutral-underline background)) + (setq modus-themes-prompts '(intense bold background)) + (setq modus-themes-completions '((matches . (extrabold)) + (selection . (semibold accented)) + (popup . (accented intense)))) + + (setq modus-themes-mail-citations nil) + (setq modus-themes-region '(accented bg-only no-extend)) + (setq modus-themes-diffs 'desaturated) + (setq modus-themes-org-blocks 'gray-background) + + (setq modus-themes-org-agenda + '((header-block . (variable-pitch 1.3)) + (header-date . (grayscale workaholic bold-today 1.1)) + (event . (accented varied)) + (scheduled . uniform) + (habit . traffic-light))) + + (setq modus-themes-headings + '((0 . (variable-pitch rainbow 1.9)) + (1 . (variable-pitch rainbow 1.8)) + (2 . (variable-pitch rainbow 1.7)) + (3 . (variable-pitch rainbow bold 1.6)) + (t . (variable-pitch semilight 1.1)))) + + (setq modus-themes-scale-headings nil) + + ;;(modus-themes-load-themes) + ;;(modus-themes-load-vivendi) + ;;(modus-themes-load-operandi) +) + +(use-package ef-themes + :ensure t + :defer t + :general + (private/set-leader-keys + "Tn" '(ef-themes-select-dark :wk "night") + "Td" '(ef-themes-select-light :wk "day")) + :config + (setq ef-themes-region '('intense no-extend neutral)) + (setq ef-themes-headings ; read the manual's entry or the doc string + '((0 . (variable-pitch light 1.9)) + (1 . (variable-pitch light 1.8)) + (2 . (variable-pitch light 1.7)) + (3 . (variable-pitch semilight 1.6)) + (4 . (variable-pitch semilight 1.5)) + (5 . (variable-pitch regular 1.4)) + (6 . (variable-pitch regular 1.3)) + (7 . (variable-pitch 1.2)) ; absence of weight means `bold' + (agenda-date . (semilight 1.5)) + (agenda-structure . (variable-pitch light 1.9)) + (t . (variable-pitch 1.1)))) + (setq ef-themes-mixed-font t + ef-themes-variable-pitch-ui t) + + (defun my-ef-themes-custom-faces () + (modify-all-frames-parameters + `((right-divider-width . 1) + ;(internal-border-width . 1) + (scroll-bar-width . 0))) + + (ef-themes-with-colors + (custom-set-faces + `(aw-leading-char-face ((,c :height 3.5))) + `(header-line ((,c :box (:line-width 6 :color ,bg-main :style nil)))) + `(header-line-highlight ((,c :box (:color ,bg-main)))) + ;;`(mode-line ((,c :box (:line-width 0 :color ,bg-main :style nil)))) + ;;`(mode-line-active ((,c :box (:line-width 0 :color ,bg-main :style nil)))) + ;;`(mode-line-highlight ((,c :box (:line-width 0 :color ,bg-main)))) + ;;`(mode-line-inactive ((,c :box (:line-width 0 :color ,bg-main :style nil)))) + `(fringe ((t :background ,bg-main))) + `(window-divider ((,c :background ,bg-main :foreground ,bg-main))) + `(window-divider-first-pixel ((,c :background ,bg-main :foreground ,bg-main))) + `(window-divider-last-pixel ((,c :background ,bg-main :foreground ,bg-main))) + `(ocaml-help-face ((,c :foreground ,comment))) + `(ocaml-link-face ((,c :foreground ,link :background ,bg-main))) + `(peek-overlay-content-face ((,c :background ,bg-main)))))) + + ;;(set-face-foreground 'window-divider-first-pixel (face-attribute 'default :foreground)) + ;;(set-face-foreground 'window-divider-last-pixel (face-attribute 'default :foreground)) + + (add-hook 'ef-themes-post-load-hook #'my-ef-themes-custom-faces) + + ;(add-to-list 'ef-themes-collection 'ef-monokai-pro) + ;(add-to-list 'ef-themes-dark-themes 'ef-monokai-pro) +) + +(with-eval-after-load 'ef-themes + (put 'ef-monokai-pro 'theme-properties (list :background-mode 'dark :kind 'color-scheme :family 'ef)) + (add-to-list 'ef-themes-collection 'ef-monokai-pro) + (add-to-list 'ef-themes-dark-themes 'ef-monokai-pro) +) + +(with-eval-after-load 'ef-themes + (put 'ef-catppuccin-mocha 'theme-properties (list :background-mode 'dark :kind 'color-scheme :family 'ef)) + (add-to-list 'ef-themes-collection 'ef-catppuccin-mocha) + (add-to-list 'ef-themes-dark-themes 'ef-catppuccin-mocha) +) + +(with-eval-after-load 'ef-themes + (put 'ef-catppuccin-macchiatto 'theme-properties (list :background-mode 'dark :kind 'color-scheme :family 'ef)) + (add-to-list 'ef-themes-collection 'ef-catppuccin-macchiatto) + (add-to-list 'ef-themes-dark-themes 'ef-catppuccin-macchiatto) + (add-to-list 'ef-themes-light-themes 'ef-catppuccin-macchiatto)) + +(with-eval-after-load 'ef-themes + (put 'ef-catppuccin-frappe 'theme-properties (list :background-mode 'dark :kind 'color-scheme :family 'ef)) + (add-to-list 'ef-themes-collection 'ef-catppuccin-frappe) + (add-to-list 'ef-themes-dark-themes 'ef-catppuccin-frappe) +) + +(with-eval-after-load 'ef-themes + (put 'ef-catppuccin-latte 'theme-properties (list :background-mode 'light :kind 'color-scheme :family 'ef)) + (add-to-list 'ef-themes-collection 'ef-catppuccin-latte) + (add-to-list 'ef-themes-light-themes 'ef-catppuccin-latte) +) + +(ef-themes-select 'ef-dream) +;;(ef-themes-select 'ef-catppuccin-macchiatto) +;;(ef-themes-select 'ef-catppuccin-mocha) +;;(ef-themes-select 'ef-catppuccin-frappe) +;;(ef-themes-select 'ef-catppuccin-latte) + +(use-package general + :ensure t + :commands (private/set-leader-keys) + :demand t + :config + (general-evil-setup t) + + (general-def + [f5] #'compile + [f6] #'recompile) + + (general-create-definer + private/set-leader-keys + :states '(normal insert visual emacs) + :prefix "SPC" + :global-prefix "C-SPC") + + (general-def "C-h W" 'which-key-show-top-level) + (general-def "M-o" #'other-window + "M-O" #'tab-bar-switch-to-recent-tab) + + (private/set-leader-keys + "f" '(:ignore t :which-key "find") + "s" '(:ignore t :which-key "search") + "x" '(:ignore t :which-key "application") + "b" '(:ignore t :which-key "buffers") + "bw" '(:ignore t :which-key "windows") + "c" '(:ignore t :which-key "code") + "e" '(:ignore t :which-key "edit") + "ee" '(:ignore t :which-key "encoding") + "h" '(:ignore t :which-key "help") + "g" '(:ignore t :which-key "go to") + "m" '(:ignore t :which-key "bookmark") + "r" '(:ignore t :which-key "register")) + + (private/set-leader-keys + "" #'tab-switch + "-" #'dired-jump) + + (private/set-leader-keys + "hf" 'describe-function + "hf" 'describe-function + "hb" 'describe-bindings + "hv" 'describe-variable + "ha" 'apropos + "hk" 'describe-key + "hm" 'describe-mode + "hd" 'apropos-documentation) + + (private/set-leader-keys + "!" #'shell-command + "xq" #'restart-emacs + "xp" #'list-processes + "xP" #'proced + "xk" #'package-list-packages + + "B" 'ibuffer + "bR" 'read-only-mode + "bwu" 'winner-undo + "bwr" 'winner-redo + "bx" 'kill-buffer + "bX" 'kill-buffer-and-window + + "e SPC" 'whitespace-cleanup + "eg" 'mark-whole-buffer + + "r SPC" 'point-to-register + "rj" 'jump-to-register + "rw" 'window-configuration-to-register + + "Tf" 'toggle-frame-fullscreen + "Tm" 'toggle-frame-maximized + "Tt" 'text-scale-adjust)) + +;; evil-want-keybinding must be declared before Evil and Evil Collection +(setq evil-want-keybinding nil) + +(use-package evil + :ensure t + :demand t + :init + (setq evil-want-integration t) + (setq evil-want-keybinding nil) + :diminish evil-escape-mode + :custom + (evil-want-C-u-scroll t) + ;;(evil-want-C-d-scroll t) + ;(evil-want-C-i-jump t) + (evil-want-C-h-delete t) + (evil-want-Y-yank-to-eol t) + (evil-respect-visual-line-mode t) + (evil-want-fine-undo t) + (evil-kill-on-visual-paste nil) + (evil-auto-balance-windows t) + (evil-auto-indent t) + + ;; Move back the cursor one position when exiting insert mode + (evil-move-cursor-back nil) + (evil-move-beyond-eol nil) + :general + (general-def "C-M-u" #'universal-argument) + ;(general-def "" 'keyboard-escape-quit) + (general-imap "C-g" #'evil-normal-state) + + ;; exit out of a transient with escape + (general-def :keymaps 'transient-map "" #'transient-quit-one) + + ;;(general-def :keymaps 'evil-ex-search-keymap "" 'keyboard-escape-quit) + ;;(general-def :keymaps 'evil-ex-search-keymap "C-g" 'keyboard-escape-quit) + + ;;(general-imap "C-h" 'evil-delete-backward-char-and-join) + ;;(general-mmap "j" 'evil-next-visual-line) + ;;(general-mmap "k" 'evil-previous-visual-line) + (general-mmap "zn" #'narrow-to-defun) + (general-vmap "zn" #'narrow-to-region) + (general-mmap "zw" #'widen) + (general-nmap "-" #'dired-jump) + + (:keymaps 'evil-ex-map + "wq" 'unpackaged/save-and-kill-buffer + "tp" 'tab-previous + "tn" 'tab-next) + + (:keymaps 'evil-window-map + "f" #'tab-bar-new-tab) + + ;; Use visual line motions even outside of visual-line-mode buffers + (general-mmap + "j" 'evil-next-visual-line + "k" 'evil-previous-visual-line) + + (private/set-leader-keys + "" #'evil-ex-nohighlight + "u" 'universal-argument + "w" '(evil-window-map :which-key "window") + "S" '(evil-write-all :which-key "save all") + "`" 'evil-switch-to-windows-last-buffer) + + (general-vmap + :prefix "SPC" + "y" (general-simulate-key "\"+y" :state 'visual) + "P" (general-simulate-key "\"_dP" :state 'visual) + "d" (general-simulate-key "\"_d" :state 'visual)) + + (general-nmap + :prefix "SPC" + "y" (general-simulate-key "\"+y" :state 'normal) + "Y" (general-simulate-key "\"+Y" :state 'normal) + "d" (general-simulate-key "\"_d" :state 'normal)) + + :config + (evil-set-undo-system 'undo-redo) + (evil-set-initial-state 'eat-mode 'insert) + + ;; this mirrors the minibuffer in nvim better escape should exit the minibuffer + (add-hook 'minibuffer-mode-hook + (lambda () + (evil-local-set-key 'insert (kbd "") 'keyboard-escape-quit) + (evil-local-set-key 'normal (kbd "") 'keyboard-escape-quit))) + + (defun sjb/evil-scroll-line-to-center (&rest _) + (evil-scroll-line-to-center nil)) + + (advice-add 'evil-search-next :after #'sjb/evil-scroll-line-to-center) + (advice-add 'evil-search-previous :after #'sjb/evil-scroll-line-to-center) + + (advice-add 'evil-scroll-down :after #'sjb/evil-scroll-line-to-center) + (advice-add 'evil-scroll-up :after #'sjb/evil-scroll-line-to-center) + + (defalias #'forward-evil-word #'forward-evil-symbol) + ;; make evil-search-word look for symbol rather than word boundaries + (setq evil-symbol-word-search t) + + (evil-define-operator my-evil-comment-or-uncomment (beg end) + "Toggle comment for the region between BEG and END." + (interactive "") + (comment-or-uncomment-region beg end)) + (evil-define-key 'normal 'global (kbd "gc") 'my-evil-comment-or-uncomment) + + (defun unpackaged/save-and-kill-buffer () + (interactive) + (save-buffer) + (kill-this-buffer)) + + (setq org-fold-core-style 'overlays) + (evil-mode +1) + ;; Make evil serch more like vim + (evil-select-search-module 'evil-search-module 'evil-search) + (setq search-invisible 'open)) + +(use-package evil-collection + :ensure t + :after evil + :hook ((eshell-first-time-mode . evil-collection-eshell-setup) + (after-init . evil-collection-init)) + :custom + (evil-collection-outline-bind-tab-p t) + (evil-collection-setup-minibuffer t) + (forge-add-default-bindings nil) + (evil-collection-magit-use-z-for-folds nil) + :general + ;;(general-def :keymaps 'evil-window-map "d" 'evil-window-delete) + ;;(general-def :keymaps 'evil-window-map "=" 'balance-windows-area) + + (private/set-leader-keys + "'" '(evil-collection-consult-mark :wk "list mark")) + + :config + + (with-eval-after-load 'dired + (evil-collection-define-key 'normal 'dired-mode-map + "h" 'dired-single-up-directory + "l" 'dired-single-buffer) + + (evil-collection-define-key 'normal 'dired-mode-map + "i" 'wdired-change-to-wdired-mode + "gF" 'multi-dired-find-file + "C-o" 'dired-find-file-below)) + + (with-eval-after-load 'mu4e + (evil-collection-define-key 'motion 'mu4e-view-mode-map + "go" 'mu4e-view-go-to-url + "gO" 'mu4e-view-go-to-url-gui)) + + (with-eval-after-load 'epa + (evil-collection-define-key 'normal 'epa-key-list-mode-map + "m" 'epa-mark-key + "u" 'epa-unmark-key))) + +(use-package evil-matchit + :ensure t + :defer 1 + :hook (after-init . global-evil-matchit-mode) + :after evil) + +(use-package evil-surround + :ensure t + :defer t + :commands global-evil-surround-mode + :hook (after-init . global-evil-surround-mode) + :after evil) + +(use-package evil-multiedit + :ensure t + :after evil + :defer t + :custom + (evil-multiedit-use-symbols 1) + :general + (general-evil-define-key 'normal 'global + (kbd "M-d") #'evil-multiedit-match-symbol-and-next + (kbd "M-D") #'evil-multiedit-match-symbol-and-prev) + (general-evil-define-key 'visual 'global + "R" #'evil-multiedit-match-all + (kbd "M-d") #'evil-multiedit-match-and-next + (kbd "M-D") #'evil-multiedit-match-and-prev) + (general-evil-define-key '(visual normal) 'global + (kbd "C-M-d") #'evil-multiedit-restore) + + (general-evil-define-key 'multiedit 'global + (kbd "M-d") #'evil-multiedit-match-and-next + (kbd "M-S-d") #'evil-multiedit-match-and-prev + (kbd "RET") #'evil-multiedit-toggle-or-restrict-region) + + (general-evil-define-key '(multiedit multiedit-insert) 'global + (kbd "C-n") #'evil-multiedit-next + (kbd "C-p") #'evil-multiedit-prev)) + +(use-package evil-textobj-tree-sitter + :vc (evil-textobj-tree-sitter :url "https://github.com/meain/evil-textobj-tree-sitter.git" :branch "auto-update-queries") + :ensure t + :defer t + :general + (:keymaps 'evil-outer-text-objects-map + "a" (evil-textobj-tree-sitter-get-textobj "parameter.outer") + "b" (evil-textobj-tree-sitter-get-textobj "block.outer") + "c" (evil-textobj-tree-sitter-get-textobj "class.outer") + "f" (evil-textobj-tree-sitter-get-textobj "function.outer") + "l" (evil-textobj-tree-sitter-get-textobj ("conditional.outer" "loop.outer")) + "#" (evil-textobj-tree-sitter-get-textobj "comment.outer") + "=" (evil-textobj-tree-sitter-get-textobj "assignment.outer") + "m" (evil-textobj-tree-sitter-get-textobj "import" + '((python-ts-mode . [(import_statement) @import]) + (rust-ts-mode . [(use_declaration) @import])))) + + (:keymaps 'evil-inner-text-objects-map + "a" (evil-textobj-tree-sitter-get-textobj "parameter.inner") + "b" (evil-textobj-tree-sitter-get-textobj "block.inner") + "c" (evil-textobj-tree-sitter-get-textobj "class.inner") + "f" (evil-textobj-tree-sitter-get-textobj "function.inner") + "l" (evil-textobj-tree-sitter-get-textobj ("conditional.inner" "loop.inner")) + "#" (evil-textobj-tree-sitter-get-textobj "comment.inner")) + + (general-nmap + "]m" '((lambda () + (interactive) + (evil-textobj-tree-sitter-goto-textobj "function.outer")) :wk "function") + "[m" '((lambda () + (interactive) + (evil-textobj-tree-sitter-goto-textobj "function.outer" t)) :wk "function") + "]M" '((lambda () + (interactive) + (evil-textobj-tree-sitter-goto-textobj "function.outer" nil t)) :wk "function") + "[M" '((lambda () + (interactive) + (evil-textobj-tree-sitter-goto-textobj "function.outer" t t)) :wk "function") + "]a" '((lambda () + (interactive) + (evil-textobj-tree-sitter-goto-textobj "parameter.outer")) :wk "param") + "[a" '((lambda () + (interactive) + (evil-textobj-tree-sitter-goto-textobj "parameter.outer" t)) :wk "param") + "]A" '((lambda () + (interactive) + (evil-textobj-tree-sitter-goto-textobj "parameter.outer" nil t)) :wk "param") + "[A" '((lambda () + (interactive) + (evil-textobj-tree-sitter-goto-textobj "parameter.outer" t t)) :wk "param")) + ) + +(use-package evil-visualstar + :after evil + :ensure t + :defer t + :commands global-evil-visualstar-mode + :hook (after-init . global-evil-visualstar-mode)) + +(use-package exato + :defer t + :ensure t) + +(use-package vdiff + :ensure t + :defer t + :commands (vdiff-buffers + vdiff-buffers3 + vdiff-quit + vdiff-files + vdiff-files3) + :custom + (vdiff-auto-refine t) + (vdiff-only-highlight-refinements t)) + +(use-package fido-vertical-mode + :ensure nil + :defer t + :hook (after-init . fido-vertical-mode)) + +(use-package cape + ;; Bind dedicated completion commands + :ensure t + :defer t + :commands (cape-dabbrev cape-file cape-keyword cape-sgml cape-elisp-block) + :general + ("C-c p" '(:keymap cape-prefix-map :wk "cape")) + + (private/set-leader-keys + "k" '(:ignore t :which-key "cape") + "kp" 'completion-at-point + "kt" 'complete-tag + "kd" 'cape-dabbrev + "kf" 'cape-file + "kk" 'cape-keyword + "ks" 'cape-symbol + "ka" 'cape-abbrev + "kl" 'cape-line + "kw" 'cape-dict + "k\\" 'cape-tex + "k>" 'cape-sml + "kr" 'cape-rfc1345) + + :init + ;; Add `completion-at-point-functions', used by `completion-at-point'. + (add-to-list 'completion-at-point-functions #'cape-file) + (add-to-list 'completion-at-point-functions #'cape-dabbrev) + (add-to-list 'completion-at-point-functions #'cape-keyword) + (add-to-list 'completion-at-point-functions #'cape-sgml) + (add-to-list 'completion-at-point-functions #'cape-elisp-block) + ;;(add-to-list 'completion-at-point-functions #'cape-rfc1345) + ;;(add-to-list 'completion-at-point-functions #'cape-abbrev) + ;;(add-to-list 'completion-at-point-functions #'cape-ispell) + ;;(add-to-list 'completion-at-point-functions #'cape-dict) + ;;(add-to-list 'completion-at-point-functions #'cape-symbol) + ;;(add-to-list 'completion-at-point-functions #'cape-line) + + ;; Silence then pcomplete capf, no errors or messages! + (advice-add 'pcomplete-completions-at-point :around #'cape-wrap-silent) + + ;; Ensure that pcomplete does not write to the buffer + ;; and behaves as a pure `completion-at-point-function'. + (advice-add 'pcomplete-completions-at-point :around #'cape-wrap-purify) +) + +(defun my/ignore-elisp-keywords (cand) + (or (not (keywordp cand)) + (eq (char-after (car completion-in-region--data)) ?:))) + +(defun my/setup-elisp () + (setq-local completion-at-point-functions + (list (cape-capf-super + (cape-capf-predicate + #'elisp-completion-at-point + #'my/ignore-elisp-keywords) + #'cape-dabbrev + #'cape-file)) + cape-dabbrev-min-length 5)) + +(add-hook 'emacs-lisp-mode-hook #'my/setup-elisp) + +(use-package consult + :ensure t + :demand t + :commands (sjb-embark-preview) + :hook (completion-list-mode . consult-preview-at-point-mode) + :general + ;;(general-nmap "/" 'consult-isearch) + ("C-S-s" 'consult-line-multi + "C-c h" 'consult-history + "C-c m" 'consult-mode-command + "C-c b" 'consult-bookmark + "C-c k" 'consult-kmacrO + "C-x M-:" 'consult-complex-command + "C-x b" 'consult-buffer + "C-x 4 b" 'consult-buffer-other-window + "C-x 5 b" 'consult-buffer-other-frame + "M-#" 'consult-register-load + "M-'" 'consult-register-store + "C-M-#" 'consult-register) + + ;; Other custom bindings + ("M-y" 'consult-yank-pop) ;; orig. yank-pop + + (general-nmap "g:" #'consult-goto-line) + + (general-def :keymaps 'minibuffer-local-map "C-;" #'sjb-embark-preview) + (general-def :keymaps 'isearch-mode-map + "M-e" 'consult-isearch-history ;; orig. isearch-edit-string + "M-s e" 'consult-isearch-history ;; orig. isearch-edit-string + "M-s l" 'consult-line) ;; required by consult-line to detect isearch + + (private/set-leader-keys + "I" '(consult-imenu-multi :wk "find workspace symbols") + "i" '(consult-imenu :wk "find symbols") + "sb" '(consult-bookmark :wk "find bookmark") + "se" '(consult-compile-error :wk "find compiler error") + "sl" '(consult-line :wk "search line") + "sh" '(consult-org-heading :wk "search heading") + "sm" '(consult-mark :wk "mark") + "sr" '(consult-ripgrep :wk "grep") + "sG" '(consult-git-grep :wk "git grep") + "sK" '(consult-keep-lines :wk "keep lines") + "sL" '(consult-focus-lines :wk "focus lines") + "sM" '(consult-global-mark :wk "global mark") + "sO" '(consult-outline :wk "search outline")) + + (private/set-leader-keys + "SPC" '(consult-buffer :wk "buffers") + + "fc" '(consult-flymake :wk "flymake") + "ff" '(consult-find :wk "find file") + "fl" '(consult-locate :wk "find locate") + "fh" '(consult-man :wk "find man")) + :custom + (consult-line-numbers-widen t) + (register-preview-function #'consult-register-format) + (xref-show-xrefs-function #'consult-xref) + (xref-show-definitions-function #'consult-xref) + (xref-search-program #'ripgrep) + ;;(consult-preview-key nil) + :init + (with-eval-after-load 'project + (setq consult-project-root-function + (lambda () + (when-let (project (project-current)) + (car (project-roots project)))))) + :config + + (defun sjb-embark-preview () + "Previews candidate in vertico buffer, unless it's a consult command" + (interactive) + (unless (bound-and-true-p consult--preview-function) + (save-selected-window + (let ((embark-quit-after-action nil)) + (embark-dwim)))))) + +(use-package consult + :defer t + :commands (consult-typhoon) + :general + (private/set-leader-keys + "j" '(consult-typhoon :wk "typhoon")) + :config + (require 'consult) + (require 'project) + + (autoload 'org-buffer-list "org") + (defvar consult--source-org + `(:name "Org File" + :narrow ?o + :category file + :history file-name-history + :face consult-file + :state ,#'consult--file-state + :items ,(lambda () (mapcar #'buffer-name (org-buffer-list))) + :action ,(lambda (cand) (find-file cand)))) + + (defvar consult-project-sjb--source-file + `(:name "Project File" + :narrow (?p . "Project File") + :category file + :history file-name-history + :face consult-file + :state ,#'consult--file-state + :action ,(lambda (cand) (find-file cand)) + :enabled ,#'project-current + :items + ,(lambda () (let* ((project (project--find-in-directory (project-root (project-current)))) + (files (project-files project))) files)))) + + (defcustom consult-typhoon-sources + '(consult-project-sjb--source-file + consult--source-buffer + consult--source-bookmark + consult--source-recent-file + consult--source-org) + "Sources used by `consult-typhoon'." + :type '(repeat symbol)) + (defvar consult--typhoon-history nil) + + (defun consult-typhoon (&optional sources) + "Enhanced `switch-to-*` command" + (interactive) + (let ((selected (consult--multi (or sources consult-typhoon-sources) + :require-match + (confirm-nonexistent-file-or-buffer) + :prompt "Switch to: " + :history 'consult--typhoon-history + :sort nil))) + (unless (plist-get (cdr selected) :match) + (consult--buffer-action (car selected)))))) + +(use-package consult-project-extra + :ensure t + :after consult + :general + (general-def + [remap project-find-file] #'consult-project-extra-find) + + (general-def :keymaps 'project-prefix-map + "o" #'consult-project-extra-find-other-window)) + +(use-package consult-dir + :ensure t + :defer t + :general + (general-def [remap dired] #'consult-dir) + (:keymaps 'minibuffer-local-completion-map + "C-x C-d" 'consult-dir + "C-x C-j" 'consult-dir-jump-file)) + +(use-package consult-eglot + :ensure t + :defer t + :after (consult eglot) + :general + (:keymaps 'eglot-mode-map + [remap xref-find-apropos] #'consult-eglot-symbols) + (private/set-leader-keys + :keymaps 'eglot-mode-map + "/" '(consult-eglot-symbols :wk "symbols"))) + +(use-package consult-eglot-embark + :ensure t + :after (consult-eglot) + :config + (consult-eglot-embark-mode)) + +(use-package corfu + :general + (general-def :keymaps 'corfu-map + [remap evil-complete-next] 'corfu-next + [remap evil-complete-previous] 'corfu-previous + "RET" nil + "" nil + "TAB" nil + "C-" #'corfu-insert + "M-d" #'corfu-popupinfo-toggle + "M-n" #'corfu-popupinfo-scroll-up + "M-p" #'corfu-popupinfo-scroll-down + "C-g" #'corfu-quit + "M-l" #'corfu-show-location) + + (general-def :keymaps '(corfu-map general-override-mode-map) + :states 'insert + "C-y" #'corfu-complete + "\M-q" #'corfu-quick-complete + "\C-q" #'corfu-quick-insert + "\M-m" #'corfu-move-to-minibuffer + "M-SPC" #'corfu-insert-separator) + :custom + ;; Works with `indent-for-tab-command'. Make sure tab doesn't indent when you + ;; want to perform completion + (corfu-auto t) + (corfu-auto-prefix 3) + (corfu-auto-delay 0.5) + (corfu-echo-documentation 0.25) ; Already use corfu-doc + + (corfu-min-width 80) + (corfu-max-width corfu-min-width) ; Always have the same width + (corfu-count 14) + (corfu-scroll-margin 4) + (corfu-cycle t) + (corfu-separator ?\s) ; Necessary for use with orderless + (corfu-quit-no-match 'separator) + (corfu-quit-at-boundary 'separator) + (corfu-preview-current 'insert) ; Preview current candidate? + ;;(corfu-preselect-first t) ; Preselect first candidate? + (read-extended-command-predicate #'command-completion-default-include-p) + ;; Disable Ispell completion function. As an alternative try `cape-dict'. + (text-mode-ispell-word-completion nil) + (tab-always-indent 'complete) + + :init + (require 'corfu-quick) + (require 'corfu-history) + (require 'corfu-popupinfo) + + (global-corfu-mode 1) + (corfu-history-mode 1) + (corfu-popupinfo-mode 1) + ;;(eldoc-add-command #'corfu-insert) + + (defun corfu-enable-in-minibuffer () + "Enable Corfu in the minibuffer if `completion-at-point' is bound." + (when (where-is-internal #'completion-at-point (list (current-local-map))) + ;; (setq-local corfu-auto nil) Enable/disable auto completion + (corfu-mode 1))) + (add-hook 'minibuffer-setup-hook #'corfu-enable-in-minibuffer) + + (defun corfu-move-to-minibuffer () + (interactive) + (let ((completion-extra-properties corfu--extra) + completion-cycle-threshold completion-cycling) + (apply #'consult-completion-in-region completion-in-region--data))) +) + +(use-package embark + :ensure t + :general + (general-def + "C-h B" #'embark-bindings + "C-S-a" #'embark-act) + + (general-def :keymaps 'minibuffer-local-map + "C-." #'embark-act + "C-," #'embark-become) + + (:keymaps 'completion-list-mode-map + "C-S-a" #'embark-minimal-act) + + ([remap describe-bindings] #'embark-bindings) + + (:keymaps 'embark-collect-mode-map + "." #'embark-act + "C-a" #'embark-act + "M-t" #'toggle-truncate-lines) + :custom + (prefix-help-command #'embark-prefix-help-command) + :config + ;;(setq embark-prompter 'embark-completing-read-prompter) + (defun embark-hide-which-key-indicator (fn &rest args) + "Hide the which-key indicator immediately when using the completing-read prompter." + (which-key--hide-popup-ignore-command) + (let ((embark-indicators + (remq #'embark-which-key-indicator embark-indicators))) + (apply fn args))) + + (defun embark-which-key-indicator () + "An embark indicator that displays keymaps using which-key. + The which-key help message will show the type and value of the + current target followed by an ellipsis if there are further + targets." + (lambda (&optional keymap targets prefix) + (if (null keymap) + (which-key--hide-popup-ignore-command) + (which-key--show-keymap + (if (eq (plist-get (car targets) :type) 'embark-become) + "Become" + (format "Act on %s '%s'%s" + (plist-get (car targets) :type) + (embark--truncate-target (plist-get (car targets) :target)) + (if (cdr targets) "…" ""))) + (if prefix + (pcase (lookup-key keymap prefix 'accept-default) + ((and (pred keymapp) km) km) + (_ (key-binding prefix 'accept-default))) + keymap) + nil nil t (lambda (binding) + (not (string-suffix-p "-argument" (cdr binding)))))))) + + ;; Embark actions for this buffer/file + (defun embark-target-this-buffer-file () + (cons 'this-buffer-file (buffer-name))) + + (add-to-list 'embark-target-finders #'embark-target-this-buffer-file 'append) + (unless (member 'embark-target-this-buffer-file embark-target-finders) + (setq embark-target-finders + (append (butlast embark-target-finders 2) + '(embark-target-this-buffer-file) + (last embark-target-finders 2)))) + + (setq embark-indicators + '(embark-which-key-indicator + embark-highlight-indicator + embark-isearch-highlight-indicator)) + + + (setq embark-collect-initial-view-alist + '((consult-yank . zebra) + (consult-register . zebra) + (consult-grep . list) + (consult-location . list) + (kill-ring . zebra) + (file . list) + (buffer . list) + (symbol . list) + (t . list))) + + + (defun sudo-find-file (file) + "Open FILE as root." + (interactive "FOpen file as root: ") + (when (file-writable-p file) + (user-error "File is user writeable, aborting sudo")) + (find-file (if (file-remote-p file) + (concat "/" (file-remote-p file 'method) ":" + (file-remote-p file 'user) "@" (file-remote-p file 'host) + "|sudo:root@" + (file-remote-p file 'host) ":" (file-remote-p file 'localname)) + (concat "/sudo:root@localhost:" file)))) + + (defun sudo-this-file () + "Open the current file as root." + (interactive) + (sudo-find-file (file-truename buffer-file-name))) + + (defun my/split-window-right (&optional size) + "Split the selected window into two windows, one above the other. +The selected window is below. The newly split-off window is +below and displays the same buffer. Return the new window." + (interactive "P") + (split-window-right size) + (other-window 1)) + + (defun my/split-window-below (&optional size) + "Split the selected window into two side-by-side windows. +The selected window is on the left. The newly split-off window +is on the right and displays the same buffer. Return the new +window." + (interactive "P") + (split-window-below size) + (other-window 1)) + + (eval-when-compile + (defmacro my/embark-ace-action (fn) + `(defun ,(intern (concat "my/embark-ace-" (symbol-name fn))) () + (interactive) + (with-demoted-errors "%s" + (require 'ace-window) + (let ((aw-dispatch-always t)) + (aw-switch-to-window (aw-select nil)) + (call-interactively (symbol-function ',fn))))))) + + (eval-when-compile + (defmacro my/embark-split-below-action (fn) + `(defun ,(intern (concat "my/embark-below-" (symbol-name fn))) () + (interactive) + (split-window-below) + (other-window 1) + (call-interactively (symbol-function ',fn))))) + + (eval-when-compile + (defmacro my/embark-split-right-action (fn) + `(defun ,(intern (concat "my/embark-right" (symbol-name fn))) () + (interactive) + (split-window-right) + (other-window 1) + (call-interactively (symbol-function ',fn))))) + + (general-def :keymaps 'embark-file-map + "a" (my/embark-ace-action find-file) + "2" (my/embark-split-below-action find-file) + "3" (my/embark-split-right-action find-file)) + + (general-def :keymaps 'embark-buffer-map + "a" (my/embark-ace-action switch-to-buffer) + "2" (my/embark-split-below-action switch-to-buffer) + "3" (my/embark-split-right-action switch-to-buffer)) + + (general-def :keymaps 'embark-bookmark-map + "a" (my/embark-ace-action bookmark-jump) + "2" (my/embark-split-below-action bookmark-jump) + "3" (my/embark-split-right-action bookmark-jump)) + + ;; Hide the mode line of the Embark live/completions buffers + (add-to-list 'display-buffer-alist + '("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*" + nil + (window-parameters (mode-line-format . none))))) + +(use-package embark-consult + :ensure t + :demand t + :hook (embark-collect-mode . consult-preview-at-point-mode)) + +(use-package avy-embark-collect + :ensure t + :after embark + :general + (:keymaps 'embark-collect-mode-map + "C-'" 'avy-embark-collect-choose + "C-," 'avy-embark-collect-act)) + +(use-package marginalia + :ensure t + :hook (after-init . marginalia-mode) + :custom + (margnalia-annotators '(marginalia-annotators-heavy marginalia-annotators-light nil)) + (marginalia-max-relative-age 0) + (marginalia-align 'right) + :general (:keymaps 'minibuffer-local-map "M-A" 'marginalia-cycle)) + +(use-package orderless + :ensure t + :after corfu + :custom + (completion-styles '(orderless basic)) + (completion-category-defaults nil) + (completions-detailed t) + (completion-category-overrides '((file (styles partial-completion)))) + (orderless-component-separator 'orderless-escapable-split-on-space) + :config + (with-eval-after-load 'selectrum + (setq selectrum-highlight-candidates-function #'orderless-highlight-matches)) + + (setq orderless-matching-styles + '(orderless-prefixes + orderless-initialism + orderless-regexp)) + + (defun first-initialism (pattern index _total) + (if (= index 0) 'orderless-initialism)) + + (defun flex-if-twiddle (pattern _index _total) + (when (string-suffix-p "~" pattern) + `(orderless-flex . ,(substring pattern 0 -1)))) + + (defun without-if-bang (pattern _index _total) + (cond + ((equal "!" pattern) + '(orderless-literal . "")) + ((string-prefix-p "!" pattern) + `(orderless-without-literal . ,(substring pattern 1))))) + + (defun orderless-literal-dispatcher (pattern _index _total) + (when (string-suffix-p "=" pattern) + `(orderless-literal . ,(substring pattern 0 -1)))) + + (defun orderless-initialism-dispatcher (pattern _index _total) + (when (string-suffix-p "," pattern) + `(orderless-strict-leading-initialism . ,(substring pattern 0 -1)))) + + (setq orderless-style-dispatchers '(flex-if-twiddle + without-if-bang + orderless-literal-dispatcher + orderless-initialism-dispatcher))) + +(use-package s :defer t :ensure t) + +(use-package tabnine + :vc (tabnine :url "https://github.com/SjB/tabnine.git" :branch "change-completion-keybinding") + :hook ((prog-mode . tabnine-mode) + (kill-emacs . tabnine-kill-process)) + :after cape + :preface + (add-to-list 'completion-at-point-functions #'tabnine-completion-at-point) + :custom + (tabnine-wait 2.0) + (tabnine-idle-delay 1.0) + :config + (set-face-attribute 'tabnine-overlay-face nil :family "MonaspiceKr Nerd Font Propo") + :general + (private/set-leader-keys :keymaps 'tabnine-completion-map + "z" #'tabnine-accept-completion)) + +(use-package gptel + :defer t + :ensure t) + +(use-package chatgpt-shell + :ensure t + :general + (general-define-key + :states 'visual + :prefix "SPC" + :global-prefix "C-SPC" + "es" #'chatgpt-shell-proofread-region + "ev" #'chatgpt-shell-write-git-commit) + :config + (setq chatgpt-shell-model-versions '("gpt-3.5-turbo")) + (setq chatgpt-shell-prompt-query-response-style 'inline) + (setq chatgpt-shell-openai-key (auth-source-pick-first-password :host "api.openai.com"))) + +(use-package treesit + :demand t + :commands (treesit-install-language-grammar nf/treesit-install-all-languages) + :ensure nil + :init + ;;(add-to-list 'treesit-extra-load-path (expand-file-name "tree-sitter" user-emacs-directory)) + :config + (defun nf/treesit-install-all-languages () + "Install all languages specified by `treesit-language-source-alist'." + (interactive) + (let ((languages (mapcar 'car treesit-language-source-alist))) + (dolist (lang languages) + (treesit-install-language-grammar lang) + (message "`%s' parser was installed." lang) + (sit-for 0.75))))) + +(use-package treesit-auto + :defer 1 + :config + (setq my-elisp-ts-auto-recipe + (make-treesit-auto-recipe + :lang 'emacs-lisp + :ts-mode 'elisp-ts-mode + :remap '(elisp-mode emacs-lisp-mode) + :url "https://github.com/Wilfred/tree-sitter-elisp.git" + :revision "master" + :source-dir "src")) + (add-to-list 'treesit-auto-recipe-list my-elisp-ts-auto-recipe) + (setq my-php-ts-auto-recipe + (make-treesit-auto-recipe + :lang 'php + :ts-mode 'php-ts-mode + :remap '(php-mode) + :url "https://github.com/tree-sitter/tree-sitter-php" + :revision "master" + :source-dir "src")) + (add-to-list 'treesit-auto-recipe-list my-php-ts-auto-recipe) + (setq my-svelte-ts-auto-recipe + (make-treesit-auto-recipe + :lang 'svelte + :ts-mode 'svlte-ts-mode + :remap '(svelte-mode) + :url "https://github.com/Himujjal/tree-sitter-sveltet" + :revision "master" + :source-dir "src")) + (add-to-list 'treesit-auto-recipe-list my-svelte-ts-auto-recipe) + (setq my-sql-ts-auto-recipe + (make-treesit-auto-recipe + :lang 'sql + :ts-mode 'sql-ts-mode + :remap '(sql-mode) + :url "https://github.com/Himujjal/tree-sitter-sveltet" + :revision "master" + :source-dir "src")) + (add-to-list 'treesit-auto-recipe-list my-sql-ts-auto-recipe) + (setq my-zig-ts-auto-recipe + (make-treesit-auto-recipe + :lang 'zig + :ts-mode 'zig-ts-mode + :remap '(zig-mode) + :url "https://github.com/GrayJack/tree-sitter-zig" + :revision "master" + :source-dir "src")) + (add-to-list 'treesit-auto-recipe-list my-zig-ts-auto-recipe) + (setq my-vue-ts-auto-recipe + (make-treesit-auto-recipe + :lang 'vue + :ts-mode 'vue-ts-mode + :remap '(vue-mode) + :url "https://github.com/ikatyang/tree-sitter-vue.git" + :revision "master" + :source-dir "src")) + (add-to-list 'treesit-auto-recipe-list my-vue-ts-auto-recipe) + (setq my-ocaml-ts-auto-recipe + (make-treesit-auto-recipe + :lang 'ocaml + :ts-mode 'ocaml-ts-mode + :remap '(caml-mode tuareg-mode) + :url "https://github.com/tree-sitter/tree-sitter-ocaml.git" + :revision "master" + :source-dir "src")) + (add-to-list 'treesit-auto-recipe-list my-ocaml-ts-auto-recipe) + (setq treesit-auto-install 'prompt) + (global-treesit-auto-mode)) + +;; `M-x combobulate' (or `C-c o o') to start using Combobulate +(use-package combobulate + :defer t + :ensure t + :vc (:fetcher github :repo "mickeynp/combobulate") + ;; Optional, but recommended. + ;; + ;; You can manually enable Combobulate with `M-x + ;; combobulate-mode'. + ;;:hook (prog-mode . combobulate-mode) + ;; Amend this to the directory where you keep Combobulate's source + ;; code. +) + +(defun setup-shell() + (setq-local show-trailing-whitespace nil) + (ansi-color-for-comint-mode-on)) + + (add-hook 'shell-mode-hook 'setup-shell) + (add-hook 'term-mode-hook 'setup-shell) + + ;;(setq epg-pinentry-mode 'loopback) ; This will fail if gpg>=2.1 is not available. + ;;(pinentry-start) + + (with-eval-after-load 'tramp + (setenv "SHELL" "/bin/bash") + (setq tramp-shell-prompt-pattern "\\(?:^\\| \\)[^]#$%>\n]*#?[]#$%>] *\\(\\[[0-9;]*[a-zA-Z] *\\)*")) + + ;;(eval-after-load 'shell '(setenv "TERM" "xterm-256color")) + + (add-to-list 'comint-output-filter-functions 'ansi-color-process-output) + +(use-package shell +:ensure nil +:hook (shell-mode . my-shell-mode-hook-func) +:defer t +:config +(defun my-shell-mode-hook-func () + (set-process-sentinel (get-buffer-process (current-buffer)) + 'my-shell-mode-kill-buffer-on-exit)) + (defun my-shell-mode-kill-buffer-on-exit (process state) + (message "%s" state) + (if (or + (string-match "exited abnormally with code.*" state) + (string-match "finished" state)) + (kill-buffer (current-buffer))))) + +(use-package term + :commands term + :init + (setenv "SHELL" "/bin/bash") + (setenv "PAGER" "cat") + (setenv "EDITOR" "emacsclient") + (setq explicit-shell-file-name "/bin/bash") + (when (eq system-type 'windows-nt) + (setq explicit-shell-file-name "powershell.exe") + (setq explicit-powershell.exe-args '())) + + (add-hook 'term-mode-hook (lambda () + (goto-address-mode) + (define-key term-raw-map (kbd "M-o") 'other-window) + (setq yas-dont-activate t))) + + :config + (setq term-prompt-regexp "^[^#$%>\n]*[#$%>] *")) + +(use-package xterm-color + :ensure t + :after eshell) + +(use-package eat +:ensure t +:defer t +:hook (eshell-load-hook . (eat-eshell-mode eat-eshell-visual-command-mode))) + +(use-package eshell + :commands (eshell configure-eshell) + :hook (eshell-directory-change . sjb/sync-dir-in-buffer-name) + :custom + (eshell-scroll-to-bottom-on-input t) + (eshell-highlight-prompt nil) + (eshell-history-size 1024) + (eshell-hist-ignoredups t) + ;;(eshell-input-filter 'sjb/eshell-input-filter) + (eshell-cd-on-directory t) + (eshell-list-files-after-cd nil) + ;;(eshell-error-if-no-glob t) + ;;(eshell-review-quick-commands nil) + (eshell-prefer-lisp-functions t) + (eshell-prefer-lisp-variables t) + (eshell-ls-use-colors t) + ;;(ffap-shell-prompt-regexp nil) + (eshell-destroy-buffer-when-process-dies t) + ;;(eshell-prompt-regexp "^$ ") + (eshell-buffer-maximum-lines 10000) + + :general + (private/set-leader-keys + "xe" 'eshell) + + (:keymaps 'eshell-mode-map "C-c >" 'sjb/eshell-redirect-input) + (:keymaps 'eshell-hist-mode-map "M-r" 'consult-history) + :init + (add-hook 'eshell-mode-hook (lambda () + (setq-local completion-styles '(basic)) + (setq-local corfu-count 2) + (setq-local completion-at-point-function '(pcomplete-completions-at-point cape-file cape-history)) + (setq-local show-trailing-whitespace nil) + (setq-local outline-regexp eshell-prompt-regexp) + (evil-normalize-keymaps) + )) + + ;; We want to use xterm-256color when running interactive commands + ;; in eshell but not during other times when we might be launching + ;; a shell command to gather its output. + (add-hook 'eshell-pre-command-hook + #'(lambda () (setenv "TERM" "xterm-256color"))) + (add-hook 'eshell-post-command-hook + #'(lambda () (setenv "TERM" "dumb"))) + :config + (require 'em-tramp) + + ;;(require 'em-smart) + ;;(setq eshell-where-to-jump 'begin + ;; eshell-review-quick-commands nil + ;; eshell-scroll-to-bottom-on-input nil + ;; eshell-smart-space-goes-to-end t) + +;; If the above does not work, try uncommenting this. +;; (add-to-list 'eshell-modules-list 'eshell-smart) + (setq eshell-directory-name (expand-file-name "emacs/eshell" (xdg-data-home))) + (setq eshell-visual-commands '("tail" "top" "htop")) + + (add-to-list 'eshell-modules-list 'eshell-tramp) + ;;(add-to-list 'eshell-modules-list 'eshell-smart) + ;;(add-to-list 'eshell-output-filter-functions 'eshell-truncate-buffer) + + (defun sjb/sync-dir-in-buffer-name () + "Update eshell buffer to show directory path. +Stolen from aweshell." + (if (project-current) + (let* ((root (project-root (project-current))) + (root-name (project-name (project-current)))) + (rename-buffer (format "*eshell %s* %s" root-name (s-chop-prefix root default-directory)) t)) + (rename-buffer (format "*eshell %s*" default-directory) t))) + + (defun eshell/gst (&rest args) + (magit-status (pop args) nil) + (eshell/echo)) ;; The echo command suppresses output + + (defun eshell/clear () + "Clear the eshell buffer." + (let ((inhibit-read-only t)) + (erase-buffer) + (eshell-send-input))) + + (if (eq system-type 'darwin) + ;; The 'ls' executable requires the Gnu version on the Mac + (let ((ls (if (file-exists-p "/usr/local/bin/gls") + "/usr/local/bin/gls" + "/bin/ls"))) + (eshell/alias "ll" (concat ls " -AlohG --color=always")))) +) + +(use-package eshell-syntax-highlighting + :ensure t + :defer t + :commands unpackaged/eshell-syntax-highlighting-init + :hook (eshell-first-time-mode . unpackaged/eshell-syntax-highlighting-init) + :config + (defun unpackaged/eshell-syntax-highlighting-init () + (eshell-syntax-highlighting-global-mode +1))) + +(use-package eshell-z + :ensure t + :after eshell) + +(use-package eshell-bookmark + :hook (eshell-mode . eshell-bookmark-setup) + :after eshell) + +(use-package eshell-toggle +:ensure t +:defer t +:custom +(eshell-toggle-find-project-root-package nil) +:general + (general-def "C-x C-z" 'smart-eshell-toggle) +:config +(defun smart-eshell-toggle () + "Detect if we are in a project and dwim" + (interactive) + (if (project-current) + (setq eshell-toggle-find-project-root-package 'project) + (setq eshell-toggle-find-project-root-package nil)) + (eshell-toggle)) +) + +(use-package eshell-git-prompt + :after eshell) + +(use-package ace-link + :ensure t + :defer t + :general ((elfeed-show-mode-map org-mode-map) "M-o" 'ace-link-org) + :config + (ace-link-setup-default)) + +(use-package ace-window + :ensure t + :hook (after-init . ace-window-posframe-mode) + :commands (ace-window-prefix) + :general + ("C-x 4 o" 'ace-window-prefix) + ([remap other-window] 'ace-window) + (private/set-leader-keys "a" 'ace-window) + + :init + (setq aw-char-position 'left) + ;;(setq aw-frame-size nil) + ;;(setq aw-frame-offset '(13 . 23)) + (with-eval-after-load 'evil + (general-define-key :keymaps 'evil-window-map + "a" 'ace-window + "c" 'ace-swap-window + "x" 'ace-delete-window + "m" 'ace-maximize-window)) + :config + (defun ace-window-prefix () + "Use `ace-window' to display the buffer of the next command. + The next buffer is the buffer displayed by the next command invoked + immediately after this command (ignoring reading from the minibuffer). + Creates a new window before displaying the buffer. + When `switch-to-buffer-obey-display-actions' is non-nil, + `switch-to-buffer' commands are also supported." + (interactive) + (display-buffer-override-next-command + (lambda (buffer _) + (let (window type) + (setq + window (aw-select (propertize " ACE" 'face 'mode-line-highlight)) + type 'reuse) + (cons window type))) + nil "[ace-window]") + (message "Use `ace-window' to display next command buffer...")) + (setq aw-keys '(?a ?s ?d ?f ?g ?h ?j ?k ?l)) + (setq aw-dispatch-always nil)) + +(use-package alert + :ensure t + :commands (alert) + :init + (when (or (eq system-type 'gnu/linux) (eq system-type 'linux)) + (setq alert-default-style 'notifications)) + (when (eq system-type 'darwin) + (setq alert-default-style 'osx-notifier))) + +(use-package async + :ensure t + :defer t + :init + (async-bytecomp-package-mode 1) + :commands (async-start)) + +(use-package avy + :ensure t + :defer t + :hook (after-init . avy-setup-default) + :general + (:keymaps 'isearch-mode-map "M-j" 'avy-isearch) + ;(general-nmap "gr" '(avy-resume :wk "avy resume")) + + (private/set-leader-keys + "ec" 'avy-copy-region + "ek" 'avy-kill-region + "em" 'avy-move-region) + :config + (setq avy-background t + avy-highlight-first t + avy-style 'at-full) + + (setq avy-orders-alist + '((avy-goto-char-2 . avy-order-closest) + (avy-goto-word-1 . avy-order-closest) + (avy-goto-symbol-1 . avy-order-closest) + (avy-goto-word-or-subword-1 . avy-order-closest))) + + (with-eval-after-load 'embark + (defun avy-action-embark (pt) + (unwind-protect + (save-excursion + (goto-char pt) + (embark-act)) + (select-window + (cdr (ring-ref avy-ring 0)))) + t) + + (setf (alist-get ?\. avy-dispatch-alist) 'avy-action-embark)) + + (defun avy-action-kill-whole-line (pt) + (save-excursion + (goto-char pt) + (kill-whole-line)) + (select-window + (cdr + (ring-ref avy-ring 0))) + t) + + (setf (alist-get ?k avy-dispatch-alist) 'avy-action-kill-stay) + (setf (alist-get ?K avy-dispatch-alist) 'avy-action-kill-whole-line) + + ;; Copy text + (defun avy-action-copy-whole-line (pt) + (save-excursion + (goto-char pt) + (cl-destructuring-bind (start . end) + (bounds-of-thing-at-point 'line) + (copy-region-as-kill start end))) + (select-window + (cdr + (ring-ref avy-ring 0))) + t) + + (setf (alist-get ?w avy-dispatch-alist) 'avy-action-copy) + (setf (alist-get ?W avy-dispatch-alist) 'avy-action-copy-whole-line) + + ;; Yank text + (defun avy-action-yank-whole-line (pt) + (avy-action-copy-whole-line pt) + (save-excursion (yank)) + t) + + (setf (alist-get ?y avy-dispatch-alist) 'avy-action-yank) + (setf (alist-get ?Y avy-dispatch-alist) 'avy-action-yank-whole-line) + + ;; Transpose/Move text + (defun avy-action-teleport-whole-line (pt) + (avy-action-kill-whole-line pt) + (save-excursion (yank)) t) + + (setf (alist-get ?t avy-dispatch-alist) 'avy-action-teleport) + (setf (alist-get ?T avy-dispatch-alist) 'avy-action-teleport-whole-line) + + ;; Mark text + (defun avy-action-mark-to-char (pt) + (activate-mark) + (goto-char pt)) + + (setf (alist-get ?m avy-dispatch-alist) 'avy-action-mark-to-char) + + ;; Flyspell words + (defun avy-action-flyspell (pt) + (save-excursion + (goto-char pt) + (when (require 'flyspell nil t) + (flyspell-auto-correct-word))) + (select-window + (cdr (ring-ref avy-ring 0))) + t) + + ;; Bind to semicolon (flyspell uses C-;) + (setf (alist-get ?s avy-dispatch-alist) 'avy-action-flyspell) + + (with-eval-after-load 'dictionary + (defun dictionary-search-dwim (&optional arg) + "Search for definition of word at point. If region is active, + search for contents of region instead. If called with a prefix + argument, query for word to search." + (interactive "P") + (if arg + (dictionary-search nil) + (if (use-region-p) + (dictionary-search (buffer-substring-no-properties + (region-beginning) + (region-end))) + (if (thing-at-point 'word) + (dictionary-lookup-definition) + (dictionary-search-dwim '(4)))))) + + (defun avy-action-define (pt) + (save-excursion + (goto-char pt) + (dictionary-search-dwim)) + (select-window + (cdr (ring-ref avy-ring 0))) + t) + + (setf (alist-get ?\= avy-dispatch-alist) 'dictionary-search-dwim)) + + ;; Get Elisp Help + ;; Replace with your package manager or help library of choice + (with-eval-after-load 'helpful + + (defun avy-action-helpful (pt) + (save-excursion + (goto-char pt) + (helpful-at-point)) + (select-window + (cdr (ring-ref avy-ring 0))) + t) + + (setf (alist-get ?H avy-dispatch-alist) 'avy-action-helpful)) + + ;; Isearch in other windows + (defun isearch-forward-other-window (prefix) + "Function to isearch-forward in other-window." + (interactive "P") + (unless (one-window-p) + (save-excursion + (let ((next (if prefix -1 1))) + (other-window next) + (isearch-forward) + (other-window (- next)))))) + + (defun isearch-backward-other-window (prefix) + "Function to isearch-backward in other-window." + (interactive "P") + (unless (one-window-p) + (save-excursion + (let ((next (if prefix 1 -1))) + (other-window next) + (isearch-backward) + (other-window (- next)))))) + + (define-key global-map (kbd "C-M-s") 'isearch-forward-other-window) + (define-key global-map (kbd "C-M-r") 'isearch-backward-other-window) + + (with-eval-after-load 'lsp-mode + (defun avy-action-lsp-describe (pt) + (save-excursion + (goto-char pt) + (lsp-describe-thing-at-point)) + (select-window + (cdr (ring-ref avy-ring 0))) + t) + + (setf (alist-get ?L avy-dispatch-alist) 'avy-action-lsp-describe))) + +(use-package evil-avy + :ensure t + :general + + (general-def [remap evil-find-char] 'evil-avy-goto-char) + (general-def [remap evil-find-char-to] 'evil-avy-goto-word-or-subword-1) + ;;(general-nmap "g:" '(evil-avy-goto-line :wk "go to line")) + (general-nmap "gs" '(evil-avy-goto-symbol-1 :wk "go to symbol")) + + (private/set-leader-keys + "gw" '(evil-avy-goto-word-0 :wk "jump to word") + "gl" '(evil-avy-goto-line :wk "jump to line"))) + + ;; (with-eval-after-load 'eww-mode + ;; (general-def 'motion eww-mode-map + ;; "S" 'evil-avy-goto-char-timer + ;; "s" 'evil-avy-goto-char-in-line)) + + + +(use-package beginend + :ensure t + :hook (prog-mode . beginend-prog-mode)) + +(use-package bookmark + :defer t + :custom + (bookmark-sort-flag nil) + :preface + (setq bookmark-default-file (expand-file-name "emacs/bookmarks.el" (xdg-data-home))) + (defun jump-to-numbered-bookmark (num) + "Jump to the bookmark with the given numeric prefix." + (let ((bookmark (nth num bookmark-alist))) + (when bookmark + (bookmark-jump bookmark)))) + :general + + (private/set-leader-keys + "mm" 'bookmark-set + "mS" 'bookmark-save + "ml" 'bookmark-bmenu-list + + "@" '(point-to-register :wk "mark") + ";" '(jump-to-register :wk "jump") + "," '((lambda () (interactive) (bookmark-set (sjb/get-bookmark-name))) :wk "bookmark")) + +;; (private/set-leader-keys +;; "0" '(bookmark-bmenu-list :wk "view harpoon list") +;; "1" '((lambda () (interactive) (jump-to-numbered-bookmark 0)) :wk "harpoon 1") +;; "2" '((lambda () (interactive) (jump-to-numbered-bookmark 1)) :wk "harpoon 2") +;; "3" '((lambda () (interactive) (jump-to-numbered-bookmark 2)) :wk "harpoon 3") +;; "4" '((lambda () (interactive) (jump-to-numbered-bookmark 3)) :wk "harpoon 4") +;; "5" '((lambda () (interactive) (jump-to-numbered-bookmark 4)) :wk "harpoon 5") +;; "6" '((lambda () (interactive) (jump-to-numbered-bookmark 5)) :wk "harpoon 6") +;; "7" '((lambda () (interactive) (jump-to-numbered-bookmark 6)) :wk "harpoon 7") +;; "8" '((lambda () (interactive) (jump-to-numbered-bookmark 7)) :wk "harpoon 8") +;; "9" '((lambda () (interactive) (jump-to-numbered-bookmark 8)) :wk "harpoon 9")) + +:init + (add-hook 'bookmark-bmenu-mode-hook #'hl-line-mode) + (defun sjb/get-bookmark-name () + (let* ((name + (if (treesit-language-at (point)) + (treesit-add-log-current-defun) + " ")) + (mark (concat (format-mode-line "harpoon| %b:%l [%p] ") name))) + (message "%s" mark) + mark))) + +(use-package bookmark-in-project + :ensure t + :defer t + :general + (private/set-leader-keys + "mn" 'bookmark-in-project-jump-next + "mp" 'bookmark-in-project-jump-previous + "mg" 'bookmark-in-project-jump + "z" 'bookmark-in-project-toggle)) + +(use-package breadcrumb-mode + :after eglot + :vc (:fetcher github :repo "joaotavora/breadcrumb") + :hook (eglot-managed-mode . breadcrumb-local-mode)) + +(use-package buffer-name-relative +:after project +:config +(buffer-name-relative-mode)) + +(use-package bufler + :ensure t + :defer 1 + :general +(general-def [remap list-buffers] 'bufler) + +(general-nmap :keymaps 'bufler-list-mode-map + "gr" '(bufler :wk "Refresh") + "m" '(bufler-mode :wk "Toggle mode") + "q" '(quit-window :wk "Quit") + "SPC" '(bufler-list-buffer-peek :wk "Peek at") + "RET" '(bufler-list-buffer-switch :wk "Switch to") + "x" '(bufler-list-buffer-kill :wk "Kill") + "C-x C-s" '(bufler-list-buffer-save :wk "Save") + "N" '(bufler-list-buffer-name-workspace :wk "Named workspace") + "f" '(bufler-list-group-frame :wk "Focus on") + "F" '(bufler-list-group-make-frame :wk "Make frame"))) + +(use-package burly + :ensure t + :defer 1 + :general + (private/set-leader-keys + "mw" '(burly-bookmark-windows :wk "burly window") + "mr" '(burly-open-bookmark :wk "burly open"))) + +(use-package cheat-sh + :ensure t + :general + (private/set-leader-keys "hc" 'cheat-sh)) + +(use-package dired + :ensure nil + :defer t + :hook (dired-mode . unpackaged/dired-startup-init) + :commands (dired dired-find-file-below multi-dired-find-file wdired-change-to-wdired-mode unpackaged/dired-startup-init) + :general ("C-x j" 'dired-jump + "C-x C-j" 'dired-jump-other-window) + + :custom + (dired-dwim-target t) + (dired-listing-switches "-agho --group-directories-first") + :config + (defun unpackaged/dired-startup-init () + (dired-hide-details-mode t) + (auto-revert-mode)) + + (defun dired-clean-files () + "Perform a bunch of operations on the whitespace content of a file. + Including indent-buffer, which should not be called automatically on save." + (interactive) + (dired-map-over-marks (funcall 'dired-clean-file) nil t) + (dired-unmark-all-marks)) + + (defun dired-clean-file () + (let ((file (dired-get-filename))) + (unpackaged/process-on-file-buffer file 'unpackaged/cleanup-buffer))) + + (defun unpackaged/process-on-file-buffer (file func) + "Process func on file" + (message "%s" file) + (find-file file) + (funcall func) + (save-buffer) + (kill-buffer)) + + (defun dired-find-file-below () + "Displays file at point in a new window below current" + (interactive) + (display-buffer-below-selected (find-file-noselect (dired-get-file-for-visit)) nil)) + + (defun multi-dired-find-file (&optional arg) + "Open each of the marked files, or the file under the point, or when prefix arg, the next N files " + (interactive "P") + (let* ((fn-list (dired-get-marked-files nil arg))) + (mapc 'find-file fn-list)))) + +(use-package envrc + :ensure t + :hook (after-init . envrc-global-mode)) + +(use-package mise + :ensure t + :hook (after-init . global-mise-mode) + :custom + (mise-update-on-eshell-directory-change t) + :config + (setenv "PATH" (concat (expand-file-name "mise/shims" (xdg-data-home)) ":" (getenv "PATH"))) + (add-to-list 'exec-path '((expand-file-name "mise/shims" (xdg-data-home))))) + +(use-package drag-stuff +:ensure t +:general + (general-vmap + "J" #'drag-stuff-down + "K" #'drag-stuff-up)) + +(use-package all-the-icons-dired + :ensure t + :hook (dired-mode . all-the-icons-dired-mode)) + +(use-package nerd-icons-corfu + :ensure t + :defer 1 + :after corfu + :config + (add-to-list 'corfu-margin-formatters #'nerd-icons-corfu-formatter)) + +(use-package nerd-icons-completion + :after marginalia + :defer 1 + :config + (add-hook 'marginalia-mode-hook #'nerd-icons-completion-marginalia-setup) + (nerd-icons-completion-mode)) + +(use-package discover-my-major + :ensure t + :commands (discover-my-mode discover-my-major) + :general ("C-h C-m" 'discover-my-major + "C-h M-m" 'discover-my-mode)) + +(use-package docker + :ensure t + :defer t + :init + (with-eval-after-load 'evil + (evil-set-initial-state 'docker-images-mode 'emacs) + (evil-set-initial-state 'docker-containers-mode 'emacs) + (evil-set-initial-state 'docker-volumes-mode 'emacs) + (evil-set-initial-state 'docker-machines-mode 'emacs) + (evil-set-initial-state 'docker-netowkrs-mode 'emacs))) + +(use-package dogears + ;; These bindings are optional, of course: + :defer 1 + :hook (after-init . dogears-mode) + :general + (private/set-leader-keys + "." 'dogears-remember + "fd" 'dogears-go + "gd" 'dogears-list + "gD" 'dogears-sidebar) + + (general-nmap :keymaps 'dogears-list-mode-map + "d" #'dogears-list-delete + "" #'dogears-list-go) + :custom + ;;(dogears-idle 5) + (dogears-functions nil)) + +(use-package elfeed + :ensure t + :commands elfeed + :general + (general-nmap 'elfeed-search-mode-map + "c" 'elfeed-db-compact + "gu" 'elfeed-unjam) + (private/set-leader-keys "xf" 'elfeed) + + :config + (elfeed-org)) + + (use-package elfeed-org + :ensure t + :after elfeed + :config + (setq rmh-elfeed-org-files (list "~/.dotfiles/elfeed.org"))) + +(use-package ement +:vc (:fetcher github :repo "alphapapa/ement.el") +:general +(private/set-leader-keys + "xc" 'ement-connect)) + +(use-package emojify + :hook + (ement-room-mode . emojify-mode) + (markdown-mode . emojify-mode)) + +(use-package elisp-slime-nav + :ensure t + :commands (elisp-slime-nav-mode elisp-slime-nav-describe-elisp-thing-at-point) + :init + (dolist (hook '(emacs-lisp-mode-hook ielm-mode-hook)) + (add-hook hook 'elisp-slime-nav-mode)) + + (with-eval-after-load 'evil + (evil-define-key 'normal emacs-lisp-mode-map (kbd "K") + 'elisp-slime-nav-describe-elisp-thing-at-point)) + :config + (with-eval-after-load 'which-key + (which-key-add-key-based-replacements "C-c C-d" "elisp slime"))) + +(use-package engine-mode + :ensure t + :defer t + :general + (private/set-leader-keys "sw" '(:keymap engine-mode-prefixed-map :wk "web search")) + :config + (setq engine/browser-function 'browse-url-default-browser) + + (defengine duckduckgo "http://www.duckduckgo.com/?q=%s" :keybinding "d") + (defengine startpage "https://www.startpage.com/do/dsearch?query=%s" :keybinding "s") + (defengine gowalker "https://gowalker.org/search?q=%s" :keybinding "w") + (defengine github "https://github.com/search?ref=simplesearch&q=%s" :keybinding "g") + (defengine godoc "https://godoc.org/?q=%s") + (defengine golang "https://golang.org/?q=%s" :keybinding "z") + (defengine rustlang "https://doc.rust-lang.org/std/?search=%s" :keybinding "R") + (defengine docsrs "https://docs.rs/releases/search?query=%s&i-am-feeling-lucky=1" :keybinding "r") + (defengine msdn "https://docs.microsoft.com/en-us/dotnet/api/?view=netframework-4.7.1&term=%s" :keybinding "m")) + +(use-package erc + :ensure t + :defer t + :commands (erc-znc/dogmatix erc) + :general + (private/set-leader-keys "xi" 'erc-znc/dogmatix) + :config + (require 'erc-ring) + (erc-ring-mode t) + + (setq erc-prompt-for-password t) + ;;(make-variable-buffer-local 'erc-fill-column) + ;; (add-hook 'window-configuration-change-hook + ;; '(lambda () + ;; (save-excursion + ;; (walk-windows + ;; (lambda (w) + ;; (let ((buffer (window-buffer w))) + ;; (set-buffer buffer) + ;; (when (eq major-mode 'erc-mode) + ;; (setq erc-fill-column (- (window-width w) 2))))))))) + (defun erc-znc-connect (user host port) + (let ((pass (auth-source-pass-get 'secret (format "znc/%s@%s" user host)))) + (erc :server host :port port :nick user :password (format "%s:%s" user pass)))) + + (defun erc-znc/dogmatix () + "Connect to freenode via ZNC server at dogmatix" + (interactive) + (erc-znc-connect "sjb" "dogmatix.nca.uwo.ca" 1234)) + + (setq erc-fill-function 'erc-fill-static + erc-fill-static-center 15) + ;; (erc-autojoin-mode 1) + ;; (setq erc-autojoin-channels-alist + ;; '((".*\\.freenode.net" "#emacs" "#snappy" "#lxcontainers" "#go-nuts" "#Node.js" "#docker" "#linaro" "#linaro-tcwg"))) + (erc-track-mode 1) + (setq erc-track-exclude-type '("JOIN" "NICK" "PART" "QUIT" "MODE" + "324" "329" "332" "333" "353" "477")) + (setq erc-prompt (lambda () (concat "[" (buffer-name) "]"))) + ;;(setq erc-prompt ">") + (setq erc-hide-list '("JOIN" "PART" "QUIT" "NICK") + erc-lurker-hide-list '("JOIN" "PART" "QUIT")) + + (setq erc-default-server "irc.libera.chat") + (setq erc-prompt-for-nickserv-password t) + (setq erc-auto-query 'bury + erc-join-buffer 'bury + erc-interpret-mirc-color t + erc-rename-buffers t + erc-track-enable-keybindings nil + erc-track-visibility nil ; Only use the selected frame for visibility + erc-fill-column 80 + erc-fill-function 'erc-fill-static + erc-fill-static-center 20 + erc-autojoin-channels-alist '(("libera.chat" "#emacs" "#guix")) + erc-quit-reason (lambda (s) (or s "Fading out...")) + erc-modules + '(autoaway autojoin button completion fill irccontrols keep-place + list match menu move-to-prompt netsplit networks noncommands + readonly ring stamp track))) + + +(use-package empv + :ensure t + :defer t + :config + (add-to-list 'empv-mpv-args "--ytdl-format=best")) + +(use-package ess + :ensure t + :defer t + :mode "\\.R\\'" + :config + (setq ess-eval-visibly nil + ess-ask-for-ess-directory nil)) + +(use-package eww + :ensure t + :defer t + :general + (private/set-leader-keys + "gu" 'browse-last-url-in-browser) + :commands browse-last-url-in-browser + :hook (eww-mode . toggle-word-wrap) + :custom + (browse-url-browser-function '(("." . browse-url-default-browser))) + :config + ;;(setq browse-url-secondary-browser-function 'eww-browse-url) + (setq browse-url-secondary-browser-function 'browse-url-xdg-open) + ;;(setq browse-url-default-browser 'browser-url-firefox) + (defun browse-last-url-in-browser () + (interactive) + (save-excursion + (ffap-next t t)))) + + +(use-package exec-path-from-shell + :if (memq window-system '(mac ns x)) + :ensure t + :defer 1 + :custom + (exec-path-from-shell-variables '("SSH_AUTH_SOCK" "PATH" "MANPATH" "GOPATH" "PYTHONPATH")) + :config + (exec-path-from-shell-initialize)) + +(use-package expand-region + :ensure t + :defer t + :commands (er/expand-region) + :general + (general-vmap "v" 'er/expand-region) + :config + (with-eval-after-load 'evil + (setq expand-region-contract-fast-key "z"))) + +(use-package expreg + :ensure t + :defer t + :general + (general-vmap "." 'expreg-expand) + (general-vmap "C-." 'expreg-contract)) + +(use-package gitignore-templates + :defer t + :ensure t) + +(use-package goto-chg + :ensure t + :defer 1) + +(use-package harpoon +:ensure t +:config +(setq harpoon-cache-file (expand-file-name "emacs/harpoon/" (xdg-data-home))) +:general +(private/set-leader-keys + "ta" #'harpoon-add-file + "tf" #'harpoon-toggle-file + "tc" #'harpoon-clear + "0" #'harpoon-toggle-quick-menu + "1" #'harpoon-go-to-1 + "2" #'harpoon-go-to-2 + "3" #'harpoon-go-to-3 + "4" #'harpoon-go-to-4 + "5" #'harpoon-go-to-5 + "6" #'harpoon-go-to-6 + "7" #'harpoon-go-to-7 + "8" #'harpoon-go-to-8 + "9" #'harpoon-go-to-9)) + + +(use-package helpful + :ensure t + :general + (general-def [remap describe-command] #'helpful-command + [remap describe-function] #'helpful-callable + [remap describe-key] #'helpful-key + [remap describe-symbol] #'helpful-symbol + [remap describe-variable] #'helpful-variable) + + ("C-h f" 'helpful-callable + "C-h v" 'helpful-variable + "C-h K" 'describe-keymap) + + (:keymaps 'helpful-mode-map [remap revert-buffer] #'helpful-update) + (private/set-leader-keys "h." 'helpful-at-point) + + :init + (setq-default read-symbol-positions-list nil) + (with-eval-after-load 'evil + (add-to-list 'evil-motion-state-modes 'helpful-mode))) + +(use-package hippie-exp + :ensure nil + :general + + (general-def [remap dabbrev-expand] 'hippie-expand) + :custom + (hippie-expand-try-functions-list + '(try-complete-file-name-partially + try-complete-file-name + try-expand-dabbrev + try-expand-dabbrev-all-buffers + try-expand-dabbrev-from-kill))) + +(use-package iedit + :ensure t + :general + ("C-;" 'iedit-mode) ; also note: C-' toggles focus of matches + (:keymaps 'iedit-mode-keymap + "C-g" 'iedit-mode) ; so I can exit iedit with C-g + :config + (advice-add #'iedit--get-scope ; switch default to function scope + :filter-args + (defun my/iedit-defun-by-default (arg) + (cond ((eq (car arg) nil) '(0)) + ((eq (car arg) 0) '(nil)) + (t arg))))) + +(use-package jinx + :ensure t + :defer t + :general + ("M-$" 'jinx-correct + "C-M-$" 'jinx-languages) + :config + (with-eval-after-load 'vertico + (add-to-list 'vertico-multiform-categories + '(jinx grid (vertico-grid-annotate . 20))) + (vertico-multiform-mode 1))) + +(use-package kind-icon + :after corfu + ;; Add hook to reset cache so the icon colors match my theme + ;; NOTE 2022-02-05: This is a hook which resets the cache whenever I switch + ;; the theme using my custom defined command for switching themes. If I don't + ;; do this, then the backgound color will remain the same, meaning it will not + ;; match the background color corresponding to the current theme. Important + ;; since I have a light theme and dark theme I switch between. This has no + ;; function unless you use something similar + :hook (after-load-theme . (lambda () (interactive) (kind-icon-reset-cache))) + :custom + (kind-icon-use-icons t) + (kind-icon-default-face 'corfu-default) ; Have background color be the same as `corfu' face background + (kind-icon-blend-background nil) ; Use midpoint color between foreground and background colors ("blended")? + (kind-icon-blend-frac 0.08) + :config + (add-to-list 'corfu-margin-formatters #'kind-icon-margin-formatter) ; Enable `kind-icon' + (add-to-list 'kind-icon-mapping '(tabnine "ai" :icon "cloud" :face shadow) t)) + +(use-package link-hint + :ensure t + :defer t + :general + (private/set-leader-keys + "elo" 'link-hint-open-link + "elc" 'link-hist-open-copy)) + +(use-package lxc + :defer t + :ensure t) + +(use-package lxc-tramp + :defer 1 + :ensure t) + +(use-package lxd-tramp + :defer 1 + :ensure t) + +(use-package incus-tramp + :ensure nil + :after tramp + :config + (incus-tramp-add-method) + (tramp-set-completion-function incus-tramp-method + '((incus-tramp-completion-function-alist))) + ) + +(setq mail-user-agent 'mu4e-user-agent) + (use-package mu4e + :if (eq system-type 'gnu/linux) + :ensure nil + :defer t + :hook (mu4e-compose-mode . turn-on-auto-fill) + :general + (private/set-leader-keys "xm" 'mu4e) + :custom + (mu4e-maildir "~/.maildir") + (mu4e-maildir-shortcuts nil) + (mu4e-view-prefer-html t) + (shr-color-visible-luminance-min 70) + (shr-color-visible-distance-min 80) + (mu4e-sent-messages-behavior 'sent) + (mu4e-html-renderer 'w3m) + (mu4e-change-filenames-when-moving t) + (mu4e-view-show-addresses t) + (mu4e-attachment-dir "~/Downloads") + (mu4e-get-mail-command "mbsync -a") + (mu4e-update-interval (* 5 60)) + (mu4e-decryption-policy t) + (mu4e-compose-signature-auto-include 't) + (mu4e-compose-format-flowed t) + (mml-secure-smime-sign-with-sender t) + :config + (require 'mu4e-contrib) + (require 'org-mu4e) + ;;(setq epg-debug t) + + ;;(setq mu4e-html2text-command "w3m -dump -T text/html") + ;;(setq mu4e-html2text-command 'mu4e-shr2text) + (setq smtpmail-stream-type 'starttls + smtpmail-smtp-service 587) + + (setq smtpmail-queue-mail nil) + + (setq send-mail-function 'smtpmail-send-it + message-send-mail-function 'smtpmail-send-it) + + (add-hook 'dired-mode-hook 'turn-on-gnus-dired-mode) + ;; don't keep message buffers around + (setq message-kill-buffer-on-exit t)) + + +(use-package nov + :ensure t + :mode ("\\.epub\\'" . nov-mode) + :custom + (nov-save-place-file (expand-file-name "emacs/nov-places" (xdg-cache-home))) + :config + (with-eval-after-load 'evil + (evil-set-initial-state 'nov-mode 'emacs)) + :preface + (defun my-nov-setup () + (visual-line-mode 1) + (face-remap-add-relative 'variable-pitch :family "Times New Roman" :height 1.5) + (if (fboundp 'olivetti-mode) (olivetti-mode 1))) + :hook (nov-mode . my-nov-setup)) + + (use-package obsidian + :ensure t + :defer t + :custom + ;; This directory will be used for `obsidian-capture' if set. + (obsidian-inbox-directory "Inbox") + (obsidian-templates-directory "Templates") + (obsidian-daily-notes-directory "Dailies") + :general + (private/set-leader-keys + "no" #'obsidian-roam-capture + "s#" '(obsidian-search :wk "obsidian search") + "f#" '(obsidian-tag-find :wk "obsidian find")) + + (private/set-leader-keys :keymaps 'obsidian-mode-map + "go" #'obsidian-jump) + + (:keymaps 'obsidian-mode-map + ;; Replace C-c C-o with Obsidian.el's implementation. It's ok to use another key binding. + "C-c C-o" #'obsidian-follow-link-at-point + ;; Jump to backlinks + "C-c C-b" #'obsidian-backlink-jump + ;; If you prefer you can use `obsidian-insert-link' + "C-c C-l" #'obsidian-insert-wikilink) + :config + (defun obsidian-roam-capture () + "Create new obsidian note. + + In the `obsidian-inbox-directory' if set otherwise in `obsidian-directory' root." + (interactive) + (let* ((title (read-from-minibuffer "Title: ")) + (date (format-time-string "%Y%m%d%H%M%S")) + (filename (s-concat obsidian-directory "/" obsidian-inbox-directory "/" date "-" title ".md")) + (clean-filename (s-replace "//" "/" filename))) + (find-file (expand-file-name clean-filename) t) + (save-buffer) + (add-to-list 'obsidian-files-cache clean-filename))) + + (obsidian-specify-path "~/Documents/nca-notes") + (global-obsidian-mode t)) + +(use-package paren + :ensure nil + :hook (prog-mode . show-paren-mode)) + +(use-package pass + :ensure t + :defer t) + + (use-package auth-source-pass + ;; passwdstring + ;; host: host.domain.com + ;; user: user@domain.com + ;; port: 993 + :ensure t + :hook (after-init . auth-source-pass-enable) + :config + (defun auth-pass-restart () + "Restart the auth-password-store package" + (interactive) + (auth-pass-enable))) + +(use-package ob-d2 + :after org + :vc (:fetcher github :repo "dmacvicar/ob-d2") + :config + (org-babel-do-load-languages 'org-babel-load-languages '((d2 . t)))) + +(use-package plantuml-mode + :ensure t + :after org + :custom + (org-plantuml-jar-path "/usr/share/java/plantuml/plantuml.jar") + :init + (add-to-list 'org-src-lang-modes '("plantuml" . plantuml)) + (org-babel-do-load-languages 'org-babel-load-languages '((plantuml . t)))) + +(use-package pdf-tools + :mode ("\\.[pP][dD][fF]\\'" . pdf-view-mode) + :magic ("%PDF" . pdf-view-mode) + :custom + ;; PDF Files + (doc-view-continuous t) + (pdf-view-display-size 'fit-page) + (pdf-annot-activate-created-annotations t) + :preface + (defun my-pdf-set-midnight-colors () + (setq pdf-view-midnight-colors + `(,(face-foreground 'default) . ,(face-background 'default)))) + + ;; Workaround for pdf-tools not reopening to last-viewed page + ;; https://github.com/politza/pdf-tools/issues/18 + (defun my-pdf-set-last-viewed-bookmark () + (interactive) + (when (eq major-mode 'pdf-view-mode) + (bookmark-set (my-pdf-generate-bookmark-name)))) + + (defun my-pdf-jump-last-viewed-bookmark () + (when (my-pdf-has-last-viewed-bookmark) + (bookmark-jump (my-pdf-generate-bookmark-name)))) + + (defun my-pdf-has-last-viewed-bookmark () + (assoc + (my-pdf-generate-bookmark-name) bookmark-alist)) + + (defun my-pdf-generate-bookmark-name () + (concat "LAST-VIEWED: " (buffer-name))) + + (defun my-pdf-set-all-last-viewed-bookmarks () + (dolist (buf (buffer-list)) + (with-current-buffer buf + (my-pdf-set-last-viewed-bookmark)))) + :hook ((after-load-theme . my-pdf-set-midnight-colors) + (kill-buffer . my-pdf-set-last-viewed-bookmark) + (pdf-view-mode . my-pdf-jump-last-viewed-bookmark) + (kill-emacs . (lambda () + (unless noninteractive ; as `save-place-mode' does + (my-pdf-set-all-last-viewed-bookmarks))))) + :config + (require 'pdf-occur) + (define-pdf-cache-function pagelabels) + ;; (pdf-tools-install t nil t t) + ;; swiper doesn't work with pdf-tools so use normal isearch + (define-key pdf-view-mode-map (kbd "C-s") 'isearch-forward)) + +(use-package popper + :ensure t + :general + (general-nmap "gp" 'popper-toggle) + (general-def "M-`" 'popper-cycle) + (private/set-leader-keys + "bc" 'popper-cycle + "bp" 'popper-toggle-type + "bk" '(popper-kill-latest-popup :wk "kill popper") + "Tp" '(popper-toggle-latest :wk "popper")) + :defer 1 + :config + (setq popper-reference-buffers + '("\\*Messages\\*" + "^\\*Warnings\\*" + "[Oo]utput\\*$" + "^\\*Compile-Log\\*" + "^\\*Backtrace\\*" + "^\\*evil-registers``*" + "^\\*Apropos" + "^Calc:" + "^\\*Shell Command Output\\*" + "\\*[Wo]*Man.*\\*" + cheat-sh-mode + dogears-list-mode + bm-show-mode + help-mode + man-mode + helpful-mode + ibuffer-mode + occur-mode + eldoc-mode + deadgrep-mode + rg-mode + inferior-scheme-mode + term-mode + shell-mode + eshell-mode + magit-stash-mode + magit-status-mode + "magit: .*" + "\\*eshell\\*" + process-menu-mode + compilation-mode)) + (setq popper-group-function #'popper-group-by-project) + (setq popper-display-control nil) + (popper-echo-mode 1) + (popper-mode +1)) + +(use-package project + :ensure t + :demand t + :general + (private/set-leader-keys + "gp" '(project-switch-project :wk "project") + "p" '(:keymap project-prefix-map :wk "project")) + + (general-def :keymaps 'project-prefix-map + "a" 'sjb/project-add-git-repo + "." #'flymake-show-project-diagnostics + "L" 'project-remember-projects-under + "X" 'project-forget-project + "Z" 'project-forget-zombie-projects) + + :config + + (defun sjb/set-tab-bar-name-to-project (&rest _) + (when (project-current) + (tab-bar-rename-tab (project-root (project-current))))) + (advice-add 'project-switch-project :after #'sjb/set-tab-bar-name-to-project) + + (with-eval-after-load 'magit + (defun sjb/set-frame-name-to-project (&rest _) + (set-frame-name + (concat "Project|" (project-root (project-current))))) + (advice-add 'project-switch-project :after #'sjb/set-frame-name-to-project) + + (require 'magit) + (defun sjb/project-add-git-repo () + (interactive) + (let ((project-root (magit-toplevel))) + (if (and project-root (not (member `(,project-root) project--list))) + (add-to-list 'project--list `(,project-root)) + (message "Project already in the list.")) + (project-current nil project-root) + (sjb/set-frame-name-to-project)))) + + ;; Make sure project is initialized + (project--ensure-read-project-list)) + +(use-package project-x + :vc (:fetcher github :repo "karthink/project-x") + :after project + :custom + (project-x-save-interval nil) ;Save project state every 5 min + :init + (with-eval-after-load 'project + (add-to-list 'project-switch-commands '(?j "Restore windows" project-x-windows) t) + (project-x-mode 1))) + +(use-package proced +:ensure nil +:defer t +:custom +(proced-enable-color-flag t) +(proced-tree-flag t)) + +(use-package rainbow-delimiters + :ensure t + :hook (prog-mode . rainbow-delimiters-mode)) + +(use-package rainbow-mode + :ensure t + :hook + (org-mode . rainbow-mode) + (css-mode . rainbow-mode) + (scss-mode . rainbow-mode) + (sass-mode . rainbow-mode) + (vue-mode . rainbow-mode)) + +(use-package ranger + :ensure t + :defer t + :commands (ranger deer) + :general + (private/set-leader-keys + "xr" 'ranger + "xD" 'deer) + :config + (setq ranger-hide-cursor nil)) + +(use-package recentf + :ensure nil + :defer 1 + :hook (after-init . recentf-mode) + :config + (defun my/recent-file-truename (file) + (if (or (file-remote-p file nil t) + (not (file-remote-p file))) + (file-truename file) + file)) + + (setq recentf-filename-handlers + '(substring-no-properties ;; strip out lingering text properties + my/recent-file-truename ;; resolve symlinks of local files + abbreviate-file-name) ;; replace $HOME with ~ + recentf-save-file (expand-file-name "recentf" user-emacs-directory) + recentf-auto-cleanup 'never + recentf-max-menu-items 0) + + ;; Exclude these from recentf + (dolist + (ex '("\\.gpg$" + "^/scp:" + "^/ssh:" + "^/su:" + "^/tmp/" + "^/sudo:")) + (add-to-list 'recentf-exclude ex)) + + (add-hook 'dired-mode-hook + (lambda () + (recentf-add-file default-directory))) + + (add-hook 'kill-emacs-hook #'recentf-cleanup) + (setq recentf-save-file (expand-file-name "emacs/recentf" (xdg-cache-home)))) + +(use-package request + :ensure t + :defer t + :custom + (request-storage-directory (expand-file-name "emacs/request" (xdg-data-home)))) + +(use-package restclient + :defer t + :ensure t) + +(use-package ob-restclient + :ensure t + :defer t + :after org + :init + (with-eval-after-load 'org + (require 'ob-restclient))) + +(use-package rg + :ensure t + :defer t + :general + (private/set-leader-keys + "s'" 'rg + "s." 'rg-dwim)) + +(use-package saveplace + :hook ((after-init . savehist-mode) + (after-init . save-place-mode)) + :custom + (save-place t)) + +(use-package sidecar-locals + :defer 1 + :hook (after-init . sidecar-locals-mode) + :config + (setq sidecar-locals-paths-allow + (list "/home/sjb/Projects/"))) + +(use-package shackle + :ensure + :diminish + :hook (after-init . shackle-mode) + :config + (defun my-split-window-sensibly (&optional window) + "replacement `split-window-sensibly' function which prefers vertical splits" + (interactive) + (let ((window (or window (selected-window)))) + (or (and (window-splittable-p window t) + (with-selected-window window + (split-window-right))) + (and (window-splittable-p window) + (with-selected-window window + (split-window-below)))))) + + (setq split-window-preferred-function #'split-window-sensibly) + (setq shackle-rules '( + ("\\*Cargo.*" :regexp t :other t :select nil) + ("*Messages*" :select t :same nil :other t :popup t :inhibit-window-quit nil) + ("*Warnings*" :select nil :other t :popup t :inhibit-window-quit nil) + ("*go-guru-output*" :select t :same t) + ("*Proced*" :select t :popup t :align below) + ("*eldoc*" :select t :popup t :align right :size 0.4) + ("*Buffer List*" :select t :align below :popup t :size 0.4) + ("*evil-register* " :select nil :popup t :size 0.33) + (ibuffer-mode :same nil :select t :popup t :size 0.33) + (git-commit-mode :size 0.3 :popup t :select t) + (magit-status-mode :select t :other t :align left :size 0.33) + (magit-log-mode :align left :size 0.33 :select t) + (magit-revision-mode :same t) + (magit-process-mode :frame nil :popup t) + (magit-mode-diff :popup t :same nil :other t) + ("*Calendar*" :select t :size 0.3 :align below) + ("\\*[Wo]*Man.*\\*" :regexp t :select t :inhibit-window-quit nil :popup t :align left) + ("*info*" :select t :inhibit-window-quit t :same t) + ("\\*Async Shell.*\\*" :regexp t :ignore t ) + (" *transient*" :frame nil :popup t :select nil :align below) ; Magit helper popups + ;; ** Proced ** + (" *Marked Processes*" :frame nil :popup t :select t) + ;; ** Byte-compiler + ("*Compile-Log*" :frame nil :popup t :select t) + ;; ** Local variables warning ** + ("*Local Variables*" :same t :frame nil :popup t :select t) + ;; ** Misc ** + ("*Org PDF LaTeX Output*" :select nil) + ("*Org Preview LaTeX Output*" :select nil) + (" *undo-tree*" :frame nil) + ("*Register Preview*" :frame nil :noselect t) + (flycheck-error-list-mode :select t :align below :size 0.33) + (dired-mode :select t :other t :same t) + ((helpful-mode help-mode) :popup t :align right :inihibit-window-quit nil) + ("^\\*Dictionary\\*" :popup t :size 0.12) + (apropos-mode :select nil :popup nil :align below :size 0.2) + (special-mode :select t :popup t :size 0.33 :inhibit-window-quit nil) + (rg-mode :select t :popup t :size 0.33) + (grep-mode :select t :popup t :size 0.33) + (occur-mode :select t :popup t :size 0.33) + (completion-list-mode :select nil :popup t :align below :size 0.12) + (process-menu-mode :popup t :align below) + (compilation-mode :select nil :align below :size 0.2 :inhibit-window-quit nil))) + (setq shackle-select-reused-windows nil) ; default nil + (setq shackle-default-alignment 'right) ; default below + (setq shackle-default-size 0.4) ; default 0.5 + (setq shackle-default-rule nil)) + +(use-package super-save +:ensure t +:hook (after-init . super-save-mode)) + +(use-package texfrag +:ensure t +:hook (markdown-mode . texfrag-mode)) + +(use-package time +:ensure nil +:hook (after-init . display-time) +:custom +(display-time-day-and-date t) +(display-time-24hr-format t) +;; TODO (display-time-default-load-average t) +(display-time-use-mail-icon t) +(display-time-interval 10)) + +(use-package vterm + :ensure t + :defer t + :commands vterm + :config + ;; Speed up vterm + (setq vterm-timer-delay 0.01)) + +(use-package vundo + :defer t + :ensure t + :custom + (vundo-glyph-alist vundo-unicode-symbols)) + +(use-package uniquify + :ensure nil + :defer t + :custom + ;; TODO (uniquify-buffer-name-style 'reverse) + (uniquify-separator " • ") + (uniquify-after-kill-buffer-p t) + (uniquify-ignore-buffers-re "^\\*")) + +(use-package wgrep + :ensure t + :commands wgrep-change-to-wgrep-mode + :general (:keymaps 'grep-mode-map "C-c C-q" 'wgrep-change-to-wgrep-mode)) + +(use-package yasnippet + :ensure t + :defer 1 + :hook (after-init . yas-global-mode) + :diminish (yas-minor-mode . "γ") + :general + (general-def :keymaps 'yas-minor-mode-map + "" #'yas-expand) + + (general-def :keymaps 'yas-keymap + "C-e" 'yas/goto-end-of-active-field + "C-a" 'yas/goto-start-of-active-field + "C-n" 'yas-next-field-or-maybe-expand + "C-p" 'yas-prev-field)) + +(use-package yasnippet-snippets + :ensure t + :after yasnippet) + +(use-package yankpad + :ensure t + :commands (yankpad-expand) + :config + (setq yankpad-file "~/.dotfiles/yankpad.org") + (yankpad-reload)) + +(use-package zoxide +:hook (find-file . zoxide-add) +:general +(general-nmap "gZ" 'zoxide-find-file)) + +(use-package zoom-window + :ensure t + :commands zoom-window-zoom + :general (:keymaps 'evil-window-map "z" 'zoom-window-zoom)) + +(setq electric-pair-preserve-balance nil) + +(defun comment-auto-fill () + (setq-local comment-auto-fill-only-comments t) + (auto-fill-mode 1)) + +(defun default-prog-env-setup () + (display-line-numbers-mode 1) + ;; TODO (setq-local indent-tabs-mode nil) + (subword-mode t) + (comment-auto-fill)) + +;;(setq font-lock-maximum-decoration '((c-mode . 2) (c++-mode . 2) (t . t))) + +(add-hook 'prog-mode-hook #'default-prog-env-setup) + +(add-to-list 'auto-mode-alist '("\\.ino\\'" . c-mode)) + +(setq gdb-many-windows t + gdb-show-main t) + +(require 'ansi-color) +(add-hook 'compilation-filter-hook 'ansi-color-compilation-filter) +(add-hook 'comint-mode-hook 'ansi-color-for-comint-mode-on) + +(general-define-key :keymaps '(prog-mode-map c-mode-base-map) (kbd "C-c k") 'kill-compilation) + +;;(setq compilation-environment '("TERM=tmux-256color")) +(setq compilation-max-output-line-length nil) + +(add-hook 'compilation-mode-hook + (lambda () + ;; TODO (setq-local compilation-scroll-output t) + (setq-local scroll-conservatively most-positive-fixnum) + (setq-local scroll-margin 0))) + +(use-package eglot-booster + :after eglot + :hook (eglot-managed-mode . eglot-booster-mode) + :vc (:fetcher github :repo "sjb/eglot-booster")) + +(use-package eglot + :hook (eglot-managed-mode . sjb/setup-eglot) + :after cape + :general + (general-evil-define-key 'normal eglot-mode-map + "g=" 'eglot-format-buffer) + + (general-evil-define-key 'visual eglot-mode-map + "g=" 'eglot-format) + + (general-evil-define-key 'normal eglot-mode-map + [remap previous-error] 'flymake-goto-previous-error + [remap next-error] 'flymake-goto-next-error) + + (private/set-leader-keys + :keymaps 'eglot-mode-map + "ca" '(eglot-code-actions :wk "code actions") + "cA" '(eglot-code-action-inline :wk "code action") + "ci" '(eglot-code-action-organize-imports :wk "organize imports") + "ce" '(eglot-code-action-extract :wk "extract") + "cw" '(eglot-code-action-rewrite :wk "rewrite") + "cq" '(eglot-code-action-quickfix :wk "quickfix") + "cr" '(eglot-rename :wk "rename") + "cT" '(:ignore t :wk "toggle") + "cTi" '(eglot-inlay-hints-mode :wk "inlay hints")) + + :custom + (eglot-events-buffer-size 0) + (eglot-sync-connect nil) + (eglot-report-progress nil) + (eglot-connect-timeout nil) + (eglot-autoshutdown t) + (eglot-send-changes-idle-timeout 1) + (completion-category-defaults nil) + (eldoc-echo-area-prefer-doc-buffer t) + ;; display eldoc only in buffer not in minibuffer + ;;(eldoc-display-functions '(eldoc-display-in-buffer)) + (eldoc-documentation-strategy #'eldoc-documentation-compose) + :init + (defun sjb/setup-eglot () + ;; Optionally configure the cape-capf-buster. + ;;(add-hook 'flymake-diagnostic-functions #'eglot-flymake-backend nil t) + ;; Show flymake diagnostics first. + ;; (setq eldoc-documentation-functions + ;; (cons #'flymake-eldoc-function + ;; (remove #'flymake-eldoc-function eldoc-documentation-functions))) + ;; Show all eldoc feedback. + ;;(setq eldoc-documentation-strategy #'eldoc-documentation-compose) + ;;(eldoc-mode 1) + ;;(flymake-mode 1) + + ;;(setq-local font-lock-maximum-decoration nil) + (setq-local completion-at-point-functions + (list (cape-capf-super + #'tabnine-completion-at-point + #'eglot-completion-at-point)))) + :config + (fset #'jsonrpc--log-event #'ignore) + ;; (setq jsonrpc-event-hook nil) + ;; disable eldoc + ;;(add-to-list 'eglot-stay-out-of 'eldoc) + ;;(add-to-list 'eglot-stay-out-of 'flymake) + ;;(setq eglot-ignored-server-capabilities '(:documentHighlightProvider)) + ;; TODO (set-face-attribute 'eglot-inlay-hint-face nil :family "MonaspiceRn Nerd Font" :weight 'thin) + + (add-to-list 'eglot-server-programs + '((c++-ts-mode c-ts-mode) . ("clangd" + "-j=8" + "--compile-commands-dir=build" + "--background-index" + "--cross-file-rename" + "--completion-style=detailed" + "--inlay-hints" + "--pch-storage=memory" + "--clang-tidy"))) + ) + +(use-package dape + :defer t + :vc (:fetcher github :repo "svaante/dape")) + +(use-package compile-multi + :vc (:fetcher github :repo "mohkale/compile-multi") + :ensure t + :defer t + :general + (general-def [remap compile] #'compile-multi) + + :config + (with-eval-after-load 'project + (defun sjb/project-current-root () + (when-let (project (project-current)) + (car (project-roots project)))) + (setq compile-multi-default-directory #'sjb/project-current-root)) + + + (setq compile-multi-config '(((file-exists-p "CMakeLists.txt") + ("cmake:create" . "cmake -B build .") + ("cmake:all" . "cmake --build build --target all") + ("cmake:test" . "cmake --build build --target test")) + ((file-exists-p "Makefile") + ("make:build" . "make build") + ("make:push" . "make push") + ("make:all" . "make all")) + ((file-exists-p "Cargo.toml") + ("cargo:build" . "cargo build") + ("cargo:run" . "cargo run") + ("cargo:clean" . "cargo clean") + ("cargo:test" . "cargo test") + ("cargo:check" . "cargo check")) + ((file-exists-p "build.zig") + ("zig:build" . "zig build") + ("zig:run" . "zig run")) + ((file-expand-wildcards "*.sln") + ("dotnet:build" . "dotnet build") + ("dotnet:clean" . "dotnet clean") + ("dotnet:nuget" . "dotnet nuget locals -c all") + ("dotnet:pack" . "dotnet pack"))))) + +(use-package consult-compile-multi + :ensure t + :after consult + :after compile-multi + :defer 1 + :config + (consult-compile-multi-mode)) + +(use-package compile-multi-all-the-icons + :ensure t + :after all-the-icons-completion + :after compile-multi + :demand t) + +(use-package compile-multi-embark +:ensure t +:after embark +:after compile-multi +:demand t +:config (compile-multi-embark-mode +1)) + +(use-package dumb-jump + :hook (prog-mode . dumb-jump-mode) + ;;(xref-backend-functions . dumb-jump-xref-activate) + :general + (general-nmap "g." #'dumb-jump-go) + (private/set-leader-keys + "gq" #'dumb-jump-quick-look) + :custom + (dumb-jump-disable-obsolete-warning t) + ;;(xref-show-definitions-function #'xref-show-definitions-completing-read) + :ensure t) + +(use-package editorconfig + :ensure t + :hook (prog-mode . editorconfig-mode) + :custom + (editorconfig-get-properties-function 'editorconfig-core-get-properties-hash)) + +(use-package hideshow + :ensure t + :hook ((prog-mode emacs-lisp-mode sh-mode) . hs-minor-mode) + :config + (defvar hs-overlay-map (make-sparse-keymap) "Keymap for hs minor mode overlay.") + + (defun hs-abstract-overlay (ov) + (let* ((start (overlay-start ov)) + (end (overlay-end ov)) + (str (format " <%d lines> " (count-lines start end))) text) + (setq text (propertize str 'face 'hs-block-flag-face 'help-echo (buffer-substring (1+ start) end))) + (overlay-put ov 'display text) + (overlay-put ov 'pointer 'hand) + (overlay-put ov 'keymap hs-overlay-map))) + + (setq hs-set-up-overlay 'hs-abstract-overlay) + + (setq hs-isearch-open t)) + +(use-package ansible + :ensure t + :defer t) + +(use-package conf-mode + :mode + (;; systemd + ("\\.service\\'" . conf-unix-mode) + ("\\.timer\\'" . conf-unix-mode) + ("\\.target\\'" . conf-unix-mode) + ("\\.mount\\'" . conf-unix-mode) + ("\\.automount\\'" . conf-unix-mode) + ("\\.slice\\'" . conf-unix-mode) + ("\\.socket\\'" . conf-unix-mode) + ("\\.path\\'" . conf-unix-mode) + + ;; general + ("conf\\(ig\\)?$" . conf-mode) + ("rc\\(_local\\)?$" . conf-mode))) + +(use-package c-ts-mode + :ensure t + :defer t + :custom + (gdb-many-windows t) + (gdb-show-main t)) + +(use-package clang-format + :ensure t + :general (c-mode-base-map "C-c C-f" 'clang-format-region) + (private/set-leader-keys :keymaps 'c-mode-base-map + "bf" 'clang-format-buffer) + (general-evil-define-key 'normal c-mode-base-map + "g=" 'clang-format-buffer) + (general-evil-define-key 'visual c-mode-base-map + "g=" 'clang-format-region) + :init + (setq clang-format-executable "clang-format")) + +(use-package cmake-ts-mode + :ensure t + :mode ("\\(?:CMakeLists\\.txt\\|\\.cmake\\)\\'" . cmake-ts-mode) + :general (cmake-mode-map "C-h C-g" 'cmake-help)) + +(use-package cmake-ide + :ensure t + :hook (c-mode-common-hook . unpackaged/cmake-ide-setup) + :commands (unpackaged/cmake-ide-setup) + :general (c-mode-base-map + "C-c D" 'invoke-gdb + "C-c c" 'cmake-ide-compile) + :config + (defun unpackaged/cmake-ide-setup () + (let ((root (ignore-errors (project-current)))) + (when root + (when (file-exists-p (expand-file-name "CMakeLists.txt" root)) + (setq-local cmake-ide-build-dir (expand-file-name "build" root)) + (message "cmake : %s" root) + (cmake-ide-setup))))) + + (defun invoke-gdb () + (interactive) + (cd (cmake-ide--get-build-dir)) + (gud-gdb (concat "gdb -i=mi --fullname " (cmake-ide--get-build-dir))))) + +(use-package disaster + :ensure t + :general (c-mode-base-map "C-c a" 'disaster)) + +(add-to-list 'auto-mode-alist '("\\.definition\\'" . nxml-mode)) +(add-to-list 'auto-mode-alist '("\\.csproj\\'" . nxml-mode)) + +(use-package csharp-mode + :ensure + :init + (with-eval-after-load 'eglot + (add-to-list 'eglot-server-programs + '(csharp-ts-mode . ("csharp-ls")))) + :mode + ("\\.cs\\'" . csharp-ts-mode) + ("\\.cake\\'" . csharp-ts-mode)) + +(use-package dotnet + :ensure t + :defer t + :init + (setq dotnet-mode-keymap-prefix (kbd "C-c n"))) + +(use-package csv-mode +:ensure t +:defer t) + +(use-package dart-mode + :ensure t + :custom + (dart-sdk-path (concat (getenv "HOME") "/.flutter/bin/cache/dark-sdk/")) + :defer t) + +(use-package hover + :ensure t + :general + (:keymaps 'dart-mode-map + "C-M-z" #'hover-run-or-hot-reload + "C-M-x" #'hover-run-or-hot-restart + "C-M-p" #'hover-take-screenshot) + :init + (setq flutter-sdk-path (concat (getenv "HOME") "/.flutter") + hover-command-path (concat (getenv "HOME") "/go/bin/hover") + hover-hot-reload-on-save t + hover-screenshot-path (concat (getenv "HOME") "/Pictures") + hover-screenshot-prefix "flutter-hover-" + hover-observatory-uri "http://localhost:50300" + hover-clear-buffer-on-hot-restart t)) + +(use-package ein + :defer t + :custom + (ein:jupyter-server-use-subcommand "notebook") + (ein:output-area-inlined-images t) + :config + (require 'ein) + (require 'ein-notebook)) + +(use-package go-ts-mode + :ensure t + :mode ("\\.go\\'" . go-ts-mode) + :general (go-mode-map + "C-c C-r" 'go-run-main + "C-c C-d" 'godoc-at-point + "C-h C-g" 'godoc) + :custom + (go-play-browse-function 'browse-url) + :init + (defvar go-tools-gopath (expand-file-name "go" (getenv "HOME"))) + (defvar go-tools-bin (expand-file-name "bin" go-tools-gopath)) + :config + (setq exec-path (append exec-path (list go-tools-bin))) + + (setq gofmt-command (cond + ((executable-find "goimports") + "goimports") + (t "gofmt")))) + +(use-package js + :mode ("\\.js\\'" . js-ts-mode) + :init + (setq js-chain-indent t) + (setq js-indent-level 2) + (setq js-indent-first-init 'dynamic)) + +(use-package json-mode + :ensure t + :defer t + :mode "\\.json\\'" + :config + (with-eval-after-load 'flycheck + (setq-default flycheck-disabled-checkers + (append flycheck-disabled-checkers '(json-jsonlist))))) + +(use-package json-ts-mode + :ensure t + :mode ("\\.json\\'" . json-ts-mode)) + +(use-package julia-ts-mode + :ensure t + :mode ("\\.jl\\'" . julia-ts-mode)) + +(use-package julia-repl + :ensure t + :hook (julia-ts-mode julia-repl-mode)) + +(use-package kotlin-ts-mode + :ensure t + :mode ("\\.kt\\'" . kotlin-ts-mode)) + +(use-package lua-mode + :ensure t + :mode "\\.lua\\'") + +(use-package matlab-mode + :ensure t + :mode "\\.m\\'" + :defer t + :custom + (matlab-shell-command "~/.local/bin/matlab") + (matlab-shell-command-switches (list "-nodisplay -nosplash")) + :config + (matlab-cedet-setup)) + +(use-package markdown-mode + :ensure t + :commands (markdown-mode gfm-mode) + :custom + (markdown-enable-math t) + (markdown-enable-html t) + (markdown-fontify-code-block-natively t) + (markdown-fontify-whole-heading-line t) + (markdown-hide-markup t) + :mode (("README\\.md\\'" . gfm-mode) + ("\\.md\\'" . markdown-mode) + ("\\.text\\'" . markdown-mode) + ("\\.markdown\\'" . markdown-mode))) + +(use-package nix-mode + :ensure t + :mode ("\\.nix\\'" . nix-mode) + :config + (use-package nix-ts-mode :ensure t)) + +(use-package php-mode + :ensure t + :mode "\\.php\\'") + +(use-package pyvenv + :ensure t + :defer t + :custom + (pyvenv-menu t) + :hook ((python-ts-mode . pyvenv-mode) + (pyvenv-post-activate . pyvenv-restart-python)) + :config + ;; Setting work on to easily switch between environments + (setq pyvenv-workon "emacs") + (setenv "WORKON_HOME" (expand-file-name "~/.cache/envs/")) + (pyvenv-tracking-mode 1)) + +(use-package qml-mode + :ensure t + :mode "\\.qml\\'") + +(use-package r-ts-mode + :mode ("\\.R\\'" . r-ts-mode) + :vc (:fetcher github :repo "sje30/r-ts-mode") + :ensure t) + +;; rust-ide +(use-package rust-mode + :mode ("\\.rs\\'" . rust-mode) + :ensure t + :defer t + :custom + (rust-mode-treesitter-derive t) + :init + (setq rust-mode-treesitter-derive t) + :config + (require 'rust-compile) + (require 'rust-cargo) + (require 'rust-playpen) + (require 'rust-rustfmt) + (with-eval-after-load 'eglot + (add-to-list 'eglot-server-programs + '((rust-ts-mode rust-mode) . ("rust-analyzer" :initializationOptions + ( :procMacro (:enable t) + :cargo ( :buildScripts (:enable t) + :features "all"))))))) + +(use-package cargo + :ensure t + :hook ((rust-mode rust-ts-mode) . cargo-minor-mode) + :config + (setq exec-path (append exec-path '("~/.cargo/bin")))) + +(use-package toml-mode + :ensure t + :mode "\\.toml\\'") + +(use-package swift-mode + :ensure t + :mode "\\.swift\\'") + +(use-package typescript-ts-mode + :ensure t + :mode ("\\.ts\\'" . typescript-ts-mode) + :config + (setq typescript-indent-level 4)) + +(use-package svelte-mode + :defer t + :ensure t + :custom + (svelte-basic-offset 4)) + + +(define-derived-mode vue-mode web-mode "Vue" "Major mode for editing Vue code.") +(add-to-list 'auto-mode-alist '("\\.vue\\'" . vue-mode)) +(with-eval-after-load 'web-mode + (add-to-list 'web-mode-comment-formats '("javascript" . "//"))) + +(setq imenu-generic-expression '(("html" "^