;; Max's init.el -*- lexical-binding: t; -*- ;; General Configuration ;; set load paths for lisp evaluation (add-to-list 'load-path "~/.emacs.d/lisp/") (let ((default-directory "~/.emacs.d/lisp/")) (normal-top-level-add-subdirs-to-load-path)) (require 'go-mode) (add-to-list 'auto-mode-alist '("\\.go\\'" . go-mode)) (require 'jai-mode) (add-to-list 'auto-mode-alist '("\\.jai\\'" . jai-mode)) (require 'stupid-indent-mode) (require 'xah-find) (require 'multiple-cursors) (require 'ivy) (require 'counsel) (require 's) (require 'dash) (require 'popup) (require 'dumb-jump) (setq dumb-jump-force-searcher 'grep) (add-hook 'xref-backend-functions #'dumb-jump-xref-activate) (setq xref-show-definitions-function #'xref-show-definitions-completing-read) ;; undo-tree for persistent undo/redo (require 'queue) (require 'undo-tree) (global-undo-tree-mode) (setq undo-tree-history-directory-alist '(("." . "~/.emacs.d/undo-tree-history/"))) (setq undo-tree-auto-save-history t) (ivy-mode 1) (setq ivy-use-virtual-buffers t) (setq ivy-count-format "(%d/%d) ") ;; default indentation settings (setq-default indent-tabs-mode t) (setq-default tab-width 4) (setq-default stupid-indent-level 4) (add-hook 'text-mode-hook 'stupid-indent-mode) (add-hook 'prog-mode-hook 'stupid-indent-mode) ;; per-language indentation settings ;; (indent-tabs-mode: t = tabs, nil = spaces) (add-hook 'go-mode-hook (lambda () (setq-local indent-tabs-mode t) (setq-local tab-width 4) (setq-local stupid-indent-level 4))) (add-hook 'jai-mode-hook (lambda () (setq-local indent-tabs-mode nil) (setq-local tab-width 4) (setq-local stupid-indent-level 4))) (add-hook 'python-mode-hook (lambda () (setq-local indent-tabs-mode nil) (setq-local tab-width 4) (setq-local stupid-indent-level 4))) (add-hook 'js-mode-hook (lambda () (setq-local indent-tabs-mode nil) (setq-local tab-width 2) (setq-local stupid-indent-level 2))) (add-hook 'emacs-lisp-mode-hook (lambda () (setq-local indent-tabs-mode nil) (setq-local tab-width 2) (setq-local stupid-indent-level 2))) ;; general settings (setq-default inhibit-startup-screen t) ;; bottom panel settings (compilation, xref, etc.) (setq compilation-scroll-output t) ;; bottom panel buffer patterns (defvar my-bottom-panel-buffers '("\\*compilation\\*" "\\*xref\\*" "\\*terminal") "List of buffer name patterns for bottom panel.") (defun my-bottom-panel-buffer-p (buf) "Check if BUF is a bottom panel buffer." (seq-some (lambda (pat) (string-match-p pat (buffer-name buf))) my-bottom-panel-buffers)) ;; find existing bottom panel window (defun my-get-bottom-panel-window () "Get existing bottom panel window if any." (seq-find (lambda (w) (and (window-at-side-p w 'bottom) (my-bottom-panel-buffer-p (window-buffer w)))) (window-list))) ;; display function that reuses bottom panel (defun my-display-in-bottom-panel (buffer alist) "Display BUFFER in bottom panel, reusing existing panel window." (let ((window (my-get-bottom-panel-window))) (if window (progn (set-window-buffer window buffer) window) (let ((new-window (display-buffer-at-bottom buffer alist))) (when new-window (with-selected-window new-window (set-window-parameter new-window 'window-height 0.25))) new-window)))) ;; use our custom display function for panel buffers (add-to-list 'display-buffer-alist '("\\*compilation\\*" (my-display-in-bottom-panel) (window-height . 0.25))) (add-to-list 'display-buffer-alist '("\\*xref\\*" (my-display-in-bottom-panel) (window-height . 0.25))) ;; tab line for bottom panel (defun my-bottom-panel-tab-line () "Return tab line tabs for bottom panel buffers." (seq-filter #'my-bottom-panel-buffer-p (buffer-list))) (defun my-enable-bottom-panel-tabs () "Enable tab-line-mode for bottom panel buffers." (setq-local tab-line-tabs-function #'my-bottom-panel-tab-line) (tab-line-mode 1)) (add-hook 'compilation-mode-hook #'my-enable-bottom-panel-tabs) (add-hook 'xref--xref-buffer-mode-hook #'my-enable-bottom-panel-tabs) (add-hook 'term-mode-hook #'my-enable-bottom-panel-tabs) (defvar my-terminal-counter 0 "Counter for terminal instances.") (defun my-get-shell () "Get the shell program for the current platform." (cond ((eq system-type 'darwin) "/bin/zsh") ((eq system-type 'gnu/linux) "/bin/bash") ((eq system-type 'windows-nt) "powershell") (t "/bin/sh"))) (defun my-open-terminal () "Open first terminal in bottom panel, or create one if none exist." (interactive) (let ((existing (seq-find (lambda (buf) (string-match-p "\\*terminal" (buffer-name buf))) (buffer-list)))) (if existing (let ((win (my-display-in-bottom-panel existing '((window-height . 0.25))))) (when win (select-window win))) (my-open-terminal-new)))) (defun my-open-terminal-new () "Open a new terminal instance in bottom panel." (interactive) (let* ((default-directory (or (and (project-current) (project-root (project-current))) default-directory)) (name (format "terminal-%d" (setq my-terminal-counter (1+ my-terminal-counter)))) (buf (make-term name (my-get-shell)))) (with-current-buffer buf (term-mode) (term-char-mode)) (let ((win (my-display-in-bottom-panel buf '((window-height . 0.25))))) (when win (select-window win))))) (defun my-bottom-panel-toggle () "Toggle the bottom panel. Close if visible, open if hidden." (interactive) (let ((panel-window (my-get-bottom-panel-window))) (if panel-window (delete-window panel-window) (let ((matching-buffers (seq-filter (lambda (buf) (seq-some (lambda (pat) (string-match-p pat (buffer-name buf))) my-bottom-panel-buffers)) (buffer-list)))) (if matching-buffers (let ((win (my-display-in-bottom-panel (car matching-buffers) '((window-height . 0.25))))) (when (and win (string-match-p "\\*terminal" (buffer-name (car matching-buffers)))) (select-window win))) (message "No bottom panel buffers open.")))))) (defun my-bottom-panel-next () "Cycle to next bottom panel buffer in bottom window." (interactive) (let* ((matching-buffers (seq-filter (lambda (buf) (seq-some (lambda (pat) (string-match-p pat (buffer-name buf))) my-bottom-panel-buffers)) (buffer-list))) (bottom-window (seq-find (lambda (w) (window-at-side-p w 'bottom)) (window-list))) (current (and bottom-window (window-buffer bottom-window))) (idx (and current (seq-position matching-buffers current)))) (if (and matching-buffers bottom-window) (let ((next-buf (if idx (nth (mod (1+ idx) (length matching-buffers)) matching-buffers) (car matching-buffers)))) (set-window-buffer bottom-window next-buf)) (message "No bottom panel buffers open.")))) (add-to-list 'default-frame-alist '(fullscreen . maximized)) (show-paren-mode 1) (delete-selection-mode 1) (setq cua-auto-tabify-rectangles nil) ;; Don't tabify after rectangle commands (transient-mark-mode 1) ;; No region when it is not highlighted (setq cua-keep-region-after-copy nil) ;; don't reselect after copy (menu-bar-mode -1) (scroll-bar-mode -1) (tool-bar-mode -1) (global-auto-revert-mode t) (electric-pair-mode -1) (setq ns-pop-up-frames nil) (setq initial-major-mode 'text-mode) (setq initial-scratch-message "Just give him some food, water, and a funny hat." ) (setq ediff-split-window-function 'split-window-horizontally) (setq-default truncate-lines 1) (setq column-number-mode t) (setq dired-dnd-protocol-alist nil) (global-so-long-mode 1) (column-number-mode 1) (blink-cursor-mode 0) (setq use-dialog-box nil) (electric-indent-mode 0) (tooltip-mode -1) (setq-default select-enable-clipboard t) (setq-default x-select-enable-clipboard t) (setq-default backward-delete-char-untabify-method nil) (setq ring-bell-function 'ignore) (setq custom-file "~/.emacs.d/custom.el") ;; place custom in a separate file (setq-default require-final-newline t) (cua-mode t) (global-hl-line-mode -1) ;; backup and autosave settings (setq backup-by-copying t ; don't clobber symlinks backup-directory-alist '(("." . "~/.emacs.d/saves/")) ; don't litter my fs tree delete-old-versions t kept-new-versions 6 kept-old-versions 2 version-control t) ; use versioned backups (setq auto-save-file-name-transforms `((".*" "~/.emacs.d/saves/" t))) (setq create-lockfiles nil) ;; Recursively kill process and all descendants (defun my-kill-process-tree (pid) "Kill PID and all its descendant processes." (let ((children (split-string (shell-command-to-string (format "pgrep -P %d 2>/dev/null" pid)) "\n" t))) (dolist (child children) (when (string-match "^[0-9]+$" child) (my-kill-process-tree (string-to-number child))))) (ignore-errors (call-process "kill" nil nil nil "-9" (number-to-string pid)))) ;; Ensure all subprocesses (including grandchildren like DLV) are killed when Emacs exits (add-hook 'kill-emacs-hook (lambda () (dolist (proc (process-list)) (when (process-live-p proc) (let ((pid (process-id proc))) (when pid (my-kill-process-tree pid))) (set-process-query-on-exit-flag proc nil) (ignore-errors (delete-process proc)))))) ;; Keybindings / Keybinds ;; global (global-set-key (kbd "C-a") 'mark-whole-buffer) (global-set-key (kbd "C-n") (lambda () (interactive) (switch-to-buffer (generate-new-buffer "untitled")))) (global-set-key (kbd "S-") #'my-mouse-start-rectangle) (global-set-key (kbd "") 'my-compile-last) (global-set-key (kbd "") 'my-compile-custom) (global-set-key (kbd "") 'my-bottom-panel-toggle) (global-set-key (kbd "") 'my-bottom-panel-next) (global-set-key (kbd "C-`") 'my-open-terminal) (global-set-key (kbd "C-~") 'my-open-terminal-new) (global-set-key (kbd "") 'my-file-manager-command) (global-set-key (kbd "") 'project-switch-project) (global-set-key (kbd "") 'my-terminal-emulator-command) (global-set-key [f8] 'goto-line) (global-set-key (kbd "C-\\") 'delete-other-windows) (global-set-key (kbd "C-|") 'kill-all-buffers) (global-unset-key (kbd "C-x C-SPC")) (global-set-key (kbd "C-x C-SPC") 'rectangle-mark-mode) (global-set-key [C-return] 'save-buffer) (global-set-key [?\C-z] 'undo) (global-set-key (kbd "C-*") 'search-current-word) (global-set-key (kbd "C-/") 'comment-line) (global-set-key (kbd "M-") 'save-buffers-kill-terminal) ;; windows thing (global-set-key (kbd "C-y") 'clipboard-yank) ;; fix killring messing with system clipboard (global-set-key (kbd "C-w") 'delete-window) (global-set-key (kbd "M-w") 'clipboard-kill-ring-save) (global-set-key (kbd "M-j") 'my-duplicate-line) (global-set-key (kbd "") 'bookmark-jump) (global-set-key (kbd "") 'bookmark-set) (global-set-key (kbd "") 'toggle-frame-maximized) (global-set-key (kbd "") 'my-smart-home) (global-set-key (kbd "") 'move-end-of-line) (setq mac-command-modifier 'control) (setq mac-control-modifier 'command) ;; Restore normal cmd/ctrl in terminal buffers on macOS (when (eq system-type 'darwin) (add-hook 'term-mode-hook (lambda () (setq-local mac-command-modifier 'super) (setq-local mac-control-modifier 'control)))) ;; Enable paste in terminal (Cmd-v on macOS, C-S-v elsewhere) (add-hook 'term-mode-hook (lambda () (if (eq system-type 'darwin) (define-key term-raw-map (kbd "s-v") 'term-paste) (define-key term-raw-map (kbd "C-S-v") 'term-paste)))) ;; F5 in terminal: Ctrl-C, rebuild, enter, r, enter, c, enter (defun my-term-rebuild () "Send rebuild sequence to terminal." (interactive) (term-send-raw-string "\C-c") (sit-for 0.1) (term-send-raw-string "rebuild\r") (sit-for 0.1) (term-send-raw-string "r\r") (sit-for 0.1) (term-send-raw-string "c\r")) (add-hook 'term-mode-hook (lambda () (define-key term-raw-map (kbd "") 'my-term-rebuild))) ;; Kill terminal buffer when process exits (defun my-term-handle-exit (&optional process-name msg) "Kill terminal buffer when process exits." (when (buffer-live-p (current-buffer)) (kill-buffer (current-buffer)))) (advice-add 'term-handle-exit :after #'my-term-handle-exit) (when (eq system-type 'darwin) (global-set-key (kbd "C-") 'my-smart-home) (global-set-key (kbd "C-") 'move-end-of-line)) (global-set-key (kbd "C-f") 'my-isearch-forward) (global-set-key (kbd "C-S-f") 'my-project-find-text) (global-set-key (kbd "C-S-h") 'my-find-replace) (global-set-key (kbd "C-S-p") 'counsel-M-x) (global-set-key (kbd "C-p") 'project-find-file) (global-set-key (kbd "C-s") 'save-buffer) (global-set-key (kbd "") 'my-select-theme) (global-set-key (kbd "") 'xref-find-definitions) (global-set-key (kbd "") 'xref-pop-marker-stack) (global-set-key (kbd "C-q") 'save-buffers-kill-terminal) (global-set-key (kbd "C-l") 'my-select-line) (global-set-key (kbd "C-e") 'my-copy-path-with-line) (define-key minibuffer-local-filename-completion-map (kbd "C-2") 'my-find-file-right-pane) (define-key isearch-mode-map (kbd "") 'isearch-repeat-forward) (define-key isearch-mode-map (kbd "S-") 'isearch-repeat-backward) (define-key isearch-mode-map (kbd "") 'isearch-del-char) (define-key isearch-mode-map (kbd "") 'isearch-exit) (setq isearch-wrap-pause 'no) ;; multiple cursors (vscode-style) (setq mc/always-run-for-all t) (global-set-key (kbd "C-d") 'mc/mark-next-like-this-word) (global-set-key (kbd "C-S-d") 'mc/mark-previous-like-this-word) (global-set-key (kbd "C-S-a") 'mc/mark-all-like-this) (global-set-key (kbd "C-S-") 'mc/add-cursor-on-click) (global-set-key (kbd "C-M-") (lambda () (interactive) (mc/mark-previous-lines 1))) (global-set-key (kbd "C-M-") (lambda () (interactive) (mc/mark-next-lines 1))) (define-key mc/keymap (kbd "") 'mc/keyboard-quit) (define-key mc/keymap (kbd "") nil) ;; functions to get top panes (ignoring bottom compilation window) (defun my-get-top-windows () "Get windows in the top portion of the frame (not bottom compilation)." (let ((windows '())) (walk-windows (lambda (w) (when (window-at-side-p w 'top) (push w windows)))) (sort windows (lambda (a b) (< (car (window-edges a)) (car (window-edges b))))))) (defun my-select-left-pane () "Select the left pane of the top split." (interactive) (let ((top-windows (my-get-top-windows))) (when top-windows (select-window (car top-windows))))) (defun my-select-right-pane () "Select the right pane of the top split, creating it if needed." (interactive) (let ((top-windows (my-get-top-windows))) (if (>= (length top-windows) 2) (select-window (cadr top-windows)) (when top-windows (select-window (car top-windows)) (split-window-right) (other-window 1))))) ;; custom bind minor mode ;; this allows binding keys that override all other modes (defvar my-keys-minor-mode-map (let ((map (make-sparse-keymap))) (define-key map (kbd "M-p") 'backward-paragraph) (define-key map (kbd "M-n") 'forward-paragraph) (define-key map (kbd "C-o") 'next-multiframe-window) (define-key map (kbd "C-1") 'my-select-left-pane) (define-key map (kbd "C-2") 'my-select-right-pane) (define-key map (kbd "C-3") 'switch-to-buffer) (define-key map (kbd "C-4") 'find-file) (define-key map (kbd "C-j") 'dabbrev-expand) map) "my-keys-minor-mode keymap.") (define-minor-mode my-keys-minor-mode "A minor mode so that my key settings override annoying major modes." :init-value t :lighter "") ;; don't enable override keymap in minibuffer (defun my-minibuffer-setup-hook () (my-keys-minor-mode 0)) (add-hook 'minibuffer-setup-hook 'my-minibuffer-setup-hook) (my-keys-minor-mode 1) ;; Custom Functions ;; smart home (vscode-style) (defun my-smart-home () "Move to first non-whitespace char, or beginning of line if already there." (interactive "^") (let ((orig-point (point))) (back-to-indentation) (when (= orig-point (point)) (move-beginning-of-line 1)))) ;; project find text (literal search) (defun my-project-find-text () "Search for literal text in project." (interactive) (let ((text (read-string "Search in project: "))) (project-find-regexp (regexp-quote text)))) (defun my-project-find-word-at-point () "Search for word under cursor in project." (interactive) (let ($p1 $p2 word) (if (region-active-p) (setq $p1 (region-beginning) $p2 (region-end)) (save-excursion (skip-chars-backward "-_A-Za-z0-9") (setq $p1 (point)) (skip-chars-forward "-_A-Za-z0-9") (setq $p2 (point)))) (setq word (buffer-substring-no-properties $p1 $p2)) (when (> (length word) 0) (project-find-regexp (regexp-quote word))))) ;; compile custom command (persisted per-project) (defvar my-project-data-dir "~/.emacs.d/project-data/" "Directory to store per-project data.") (defun my-project-data-file (filename) "Get path to FILENAME for current project in project-data dir." (let* ((root (project-root (project-current t))) (hash (md5 root)) (dir (expand-file-name hash my-project-data-dir))) (unless (file-exists-p dir) (make-directory dir t)) (expand-file-name filename dir))) (defun my-compile-get-saved-command () "Get saved compile command for current project." (let ((file (my-project-data-file "compile-command"))) (when (file-exists-p file) (with-temp-buffer (insert-file-contents file) (string-trim (buffer-string)))))) (defun my-compile-save-command (cmd) "Save compile command CMD for current project." (let ((file (my-project-data-file "compile-command"))) (with-temp-file file (insert cmd)))) (defun my-compile-custom () "Run a custom compile command in the project root." (interactive) (let* ((default-directory (project-root (project-current t))) (saved (my-compile-get-saved-command)) (cmd (read-string "Command: " saved))) (my-compile-save-command cmd) (compile cmd))) (defun my-compile-last () "Run last compile command, or prompt for one if none has been run." (interactive) (let* ((default-directory (project-root (project-current t))) (cmd (my-compile-get-saved-command))) (if cmd (compile cmd) (my-compile-custom)))) ;; find and replace with modes (defun my-find-replace () "Find and replace with mode selection: project, file, or selection." (interactive) (let* ((mode (completing-read "Replace in: " '("file" "project" "selection") nil t)) (search (read-string "Find: ")) (replace (read-string (format "Replace '%s' with: " search)))) (cond ((string= mode "project") (project-query-replace-regexp (regexp-quote search) replace)) ((string= mode "file") (save-excursion (goto-char (point-min)) (query-replace search replace))) ((string= mode "selection") (if (use-region-p) (query-replace search replace nil (region-beginning) (region-end)) (message "No region selected.")))))) ;; isearch with selection (vscode-style) (defun my-isearch-forward () "Start isearch, using selected text if region is active." (interactive) (if (use-region-p) (let ((text (buffer-substring-no-properties (region-beginning) (region-end)))) (deactivate-mark) (isearch-forward nil 1) (setq isearch-string text isearch-message text) (isearch-update)) (isearch-forward))) ;; select whole line (vscode-style) (defun my-select-line () "Select the current line. Repeat to select subsequent lines." (interactive) (if (and (use-region-p) (eq last-command 'my-select-line)) (forward-line 1) (move-beginning-of-line 1) (set-mark (point)) (forward-line 1))) ;; open file in right pane from minibuffer (defvar my--find-file-right-pane nil) (defun my-find-file-right-pane () "Open file in right pane from find-file minibuffer." (interactive) (setq my--find-file-right-pane (expand-file-name (minibuffer-contents))) (abort-recursive-edit)) (defun my-find-file-right-pane-after () "Actually open the file in right pane." (when my--find-file-right-pane (let ((file my--find-file-right-pane)) (setq my--find-file-right-pane nil) (when (one-window-p) (split-window-right)) (other-window 1) (find-file file)))) (add-hook 'minibuffer-exit-hook 'my-find-file-right-pane-after) ;; theme selection (add-to-list 'custom-theme-load-path "~/.emacs.d/themes/") (defvar my-current-theme 'bedroom "Currently active theme.") (defun my-select-theme () "Select and load a theme from all available themes." (interactive) (let* ((themes (mapcar #'symbol-name (custom-available-themes))) (choice (completing-read "Theme: " themes nil t))) (when my-current-theme (disable-theme my-current-theme)) (setq my-current-theme (intern choice)) (load-theme my-current-theme t))) ;; global zoom (without resizing window) (setq frame-inhibit-implied-resize t) (defvar my-default-font-height (face-attribute 'default :height)) (defun my-global-zoom-in () (interactive) (set-face-attribute 'default nil :height (+ (face-attribute 'default :height) 10))) (defun my-global-zoom-out () (interactive) (set-face-attribute 'default nil :height (- (face-attribute 'default :height) 10))) (defun my-global-zoom-reset () (interactive) (set-face-attribute 'default nil :height my-default-font-height)) (global-set-key (kbd "C-=") 'my-global-zoom-in) (global-set-key (kbd "C--") 'my-global-zoom-out) (global-set-key (kbd "C-0") 'my-global-zoom-reset) (global-unset-key (kbd "C-x C-=")) (global-unset-key (kbd "C-x C--")) (global-unset-key (kbd "C-x C-0")) (global-set-key (kbd "C-") 'ignore) (global-set-key (kbd "C-") 'ignore) ;; test function (defun my-test () (interactive) (message "Hello world!")) ;; duplicate line (cleanly) ;; https://stackoverflow.com/questions/88399/how-do-i-duplicate-a-whole-line-in-emacs (defun my-duplicate-line (arg) "Duplicate current line, leaving point in lower line." (interactive "*p") (setq buffer-undo-list (cons (point) buffer-undo-list)) (let ((bol (save-excursion (beginning-of-line) (point))) eol) (save-excursion (end-of-line) (setq eol (point)) (let ((line (buffer-substring bol eol)) (buffer-undo-list t) (count arg)) (while (> count 0) (newline) (insert line) (setq count (1- count))) ) (setq buffer-undo-list (cons (cons eol (point)) buffer-undo-list))) ) (next-line arg)) ;; kill all buffers except current and close other panes (defun kill-all-buffers () "Kill all buffers except the current one and close other panes." (interactive) (let ((current (current-buffer))) (mapc (lambda (buf) (unless (eq buf current) (kill-buffer buf))) (buffer-list))) (delete-other-windows)) ;; delete word without copying to kill ring (defun my-delete-word (arg) "Delete characters forward until encountering the end of a word. With argument ARG, do this that many times. Does not copy to kill ring." (interactive "p") (delete-region (point) (progn (forward-word arg) (point)))) (defun my-backward-delete-word (arg) "Delete characters backward until encountering the beginning of a word. With argument ARG, do this that many times. Does not copy to kill ring." (interactive "p") (my-delete-word (- arg))) (global-set-key (kbd "M-") 'my-backward-delete-word) (global-set-key (kbd "M-d") 'my-delete-word) (global-set-key (kbd "C-") 'my-backward-delete-word) ;; copy current path with line number (defun my-copy-path-with-line () "Copy the current file path with line number to clipboard." (interactive) (if buffer-file-name (let ((path-with-line (format "%s:%d" buffer-file-name (line-number-at-pos)))) (kill-new path-with-line) (message "Copied: %s" path-with-line)) (message "Buffer has no file."))) ;; scratch buffer with recent projects (defvar my-dashboard-image "~/.emacs.d/logo.jpg" "Path to dashboard image.") (defun my-setup-scratch-buffer () "Setup scratch buffer." (with-current-buffer (get-buffer-create "*scratch*") (let ((inhibit-read-only t)) (erase-buffer) (insert "\n") ;; Image (when (and (display-graphic-p) (file-exists-p (expand-file-name my-dashboard-image))) (insert-image (create-image (expand-file-name my-dashboard-image) nil nil :height 150)) (insert "\n\n")) ;; Message (insert "Agartha needs your help! You must write a new operating system from scratch to restore Agartha's defences!\n\nYou will need some food, water, and a funny hat to complete this mission!\n") (goto-char (point-min))))) ;; select rectangle with shift+mouse (defun my-mouse-start-rectangle (start-event) (interactive "e") (deactivate-mark) (mouse-set-point start-event) (rectangle-mark-mode +1) (let ((drag-event)) (track-mouse (while (progn (setq drag-event (read-event)) (mouse-movement-p drag-event)) (mouse-set-point drag-event))))) ;; open file manager (defun my-file-manager-command () (interactive) (cond ((eq system-type 'windows-nt) (shell-command "explorer.exe .")) ((eq system-type 'darwin) (shell-command "open .")) ((eq system-type 'gnu/linux) (shell-command "setsid -f nautilus . >/dev/null 2>&1")))) ;; open terminal or cmd prompt (defun my-terminal-emulator-command () (interactive) (cond ((eq system-type 'windows-nt) (let ((proc (start-process "cmd" nil "cmd.exe" "/C" "start" "cmd.exe"))) (set-process-query-on-exit-flag proc nil))) ((eq system-type 'gnu/linux) (shell-command "setsid -f gnome-terminal . >/dev/null 2>&1")))) ;; transpose (move) windows (defun my-transpose-windows (arg) "Transpose the buffers shown in two windows." (interactive "p") (let ((selector (if (>= arg 0) 'next-window 'previous-window))) (while (/= arg 0) (let ((this-win (window-buffer)) (next-win (window-buffer (funcall selector)))) (set-window-buffer (selected-window) next-win) (set-window-buffer (funcall selector) this-win) (select-window (funcall selector))) (setq arg (if (plusp arg) (1- arg) (1+ arg)))))) ;; search current word (defun search-current-word () (interactive) (let ($p1 $p2) (if (region-active-p) (setq $p1 (region-beginning) $p2 (region-end)) (save-excursion (skip-chars-backward "-_A-Za-z0-9") (setq $p1 (point)) (right-char) (skip-chars-forward "-_A-Za-z0-9") (setq $p2 (point)))) (setq mark-active nil) (when (< $p1 (point)) (goto-char $p1)) (isearch-mode t) (isearch-yank-string (buffer-substring-no-properties $p1 $p2)))) ;; Tweaks / Fixes ;; Emacs sucks by default, here are some fixes. ;; fix isearch (defadvice isearch-search (after isearch-no-fail activate) (unless isearch-success (ad-disable-advice 'isearch-search 'after 'isearch-no-fail) (ad-activate 'isearch-search) (isearch-repeat (if isearch-forward 'forward)) (ad-enable-advice 'isearch-search 'after 'isearch-no-fail) (ad-activate 'isearch-search))) (add-hook 'isearch-mode-end-hook #'endless/goto-match-beginning) (defun endless/goto-match-beginning () "Go to the start of current isearch match. Use in `isearch-mode-end-hook'." (when (and isearch-forward (number-or-marker-p isearch-other-end) (not mark-active) (not isearch-mode-end-hook-quit)) (goto-char isearch-other-end))) ;; appearance ;; (set-face-attribute 'default nil :font "Consolas-15") (global-font-lock-mode 1) (load-theme 'bedroom t) ;; setup scratch buffer with recent projects on startup (add-hook 'emacs-startup-hook 'my-setup-scratch-buffer)