diff --git a/common/home-manager/emacs/default.nix b/common/home-manager/emacs/default.nix index 7ba6ee9..6dc98f6 100644 --- a/common/home-manager/emacs/default.nix +++ b/common/home-manager/emacs/default.nix @@ -94,6 +94,20 @@ in { (xterm-mouse-mode 1) (global-set-key (kbd "") 'scroll-down-line) (global-set-key (kbd "") 'scroll-up-line)) + + ;; git gutter with tramp + (defun git-gutter+-remote-default-directory (dir file) + (let* ((vec (tramp-dissect-file-name file)) + (method (tramp-file-name-method vec)) + (user (tramp-file-name-user vec)) + (domain (tramp-file-name-domain vec)) + (host (tramp-file-name-host vec)) + (port (tramp-file-name-port vec))) + (tramp-make-tramp-file-name method user domain host port dir))) + + (defun git-gutter+-remote-file-path (dir file) + (let ((file (tramp-file-name-localname (tramp-dissect-file-name file)))) + (replace-regexp-in-string (concat "\\`" dir) "" file))) ''; usePackageVerbose = true; @@ -134,6 +148,15 @@ in { ''; }; + crontab-mode = { + enable = true; + mode = [ + ''("\\.cron\\(tab\\)?\\'" . crontab-mode)'' + ''("cron\\(tab\\)?\\." . crontab-mode)'' + ''("/cron.d/" . crontab-mode)'' + ]; + }; + dashboard = { enable = true; config = '' @@ -156,6 +179,7 @@ in { enable = true; init = '' (setq evil-want-C-i-jump nil) + (setq evil-want-keybinding nil) ''; config = '' (evil-mode 1) @@ -164,6 +188,7 @@ in { evil-surround = { enable = true; + after = [ "evil" ]; config = '' (global-evil-surround-mode 1) ''; @@ -176,7 +201,7 @@ in { evil-magit = { enable = true; - after = [ "magit" ]; + after = [ "evil" "magit" ]; }; flycheck = { @@ -212,6 +237,13 @@ in { command = [ "lsp-ivy-workspace-symbol" ]; }; + git-gutter = { + enable = true; + config = '' + (global-git-gutter-mode +1) + ''; + }; + general = { enable = true; after = [ "evil" "which-key" ]; @@ -421,7 +453,6 @@ in { systemd.enable = true; gemini-mode.enable = true; - highlight-indent-guides.enable = true; "0x0".enable = true; request.enable = true; @@ -487,6 +518,13 @@ in { ''; }; + highlight-indent-guides = { + enable = true; + config = '' + (add-hook 'prog-mode-hook 'highlight-indent-guides-mode) + ''; + }; + nix-mode = { enable = true; mode = [ ''"\\.nix\\'"'' ]; @@ -538,6 +576,14 @@ in { }; ## custom shit + change-case = { + enable = true; + package = (epkgs: epkgs.trivialBuild { + pname = "change-case"; + src = ./packages/change-case.el; + }); + }; + xe-tools = { enable = true; package = (epkgs: epkgs.trivialBuild { @@ -545,6 +591,11 @@ in { src = ./xe-tools.el; }); + config = '' + (setq linum-format 'xe/linum-format-func) + (global-linum-mode) + ''; + bindStar = { "C-a c" = "xe/tabnew-shell"; "C-a h" = "split-window-vertically"; diff --git a/common/home-manager/emacs/packages/change-case.el b/common/home-manager/emacs/packages/change-case.el new file mode 100644 index 0000000..17b3b15 --- /dev/null +++ b/common/home-manager/emacs/packages/change-case.el @@ -0,0 +1,55 @@ +(defun camelcase-region (start end) + "Changes region from snake_case to camel_case" + (interactive "r") + (save-restriction (narrow-to-region start end) + (goto-char (point-min)) + (while (re-search-forward "_\\(.\\)" nil t) + (replace-match (upcase (match-string 1)))))) + +(defun camelcase-word-or-region () + "Changes word or region from snake_case to camel_case" + (interactive) + (let (pos1 pos2 bds) + (if (and transient-mark-mode mark-active) + (setq pos1 (region-beginning) pos2 (region-end)) + (progn + (setq bds (bounds-of-thing-at-point 'symbol)) + (setq pos1 (car bds) pos2 (cdr bds)))) + (camelcase-region pos1 pos2))) + +(defun split-name (s) + (split-string + (let ((case-fold-search nil)) + (downcase + (replace-regexp-in-string "\\([a-z]\\)\\([A-Z]\\)" "\\1 \\2" s))) + "[^A-Za-z0-9]+")) + +(defun underscore-string (s) + (mapconcat + 'downcase + (split-name s) "_")) + +(defun snakecase-region (begin end) + "Convert the given region from camel_case to snake_case" + (interactive "r") + (let* ((word (buffer-substring begin end)) + (underscored (underscore-string word))) + (save-excursion + (widen) ; break out of the subregion so we can fix every usage of the function + (replace-string word underscored nil (point-min) (point-max))))) + +(defun snakecase-word-or-region () + "Changes word or region from camel_case to snake_case" + (interactive) + (let (pos1 pos2 bds) + (if (and transient-mark-mode mark-active) + (setq pos1 (region-beginning) pos2 (region-end)) + (progn + (setq bds (bounds-of-thing-at-point 'symbol)) + (setq pos1 (car bds) pos2 (cdr bds)))) + (snakecase-region pos1 pos2))) + +(global-set-key (kbd "C-c C--") 'camelcase-word-or-region) +(global-set-key (kbd "C-c C-_") 'snakecase-word-or-region) + +(provide 'change-case) diff --git a/common/home-manager/emacs/xe-tools.el b/common/home-manager/emacs/xe-tools.el index 4bf1c51..5a53116 100644 --- a/common/home-manager/emacs/xe-tools.el +++ b/common/home-manager/emacs/xe-tools.el @@ -32,5 +32,37 @@ cell (regexp . minor-mode)." (projectile-run-vterm))) (rename-uniquely)) +(defun xe/kill-whitespace () + "Kill the whitespace between two non-whitespace characters" + (interactive "*") + (save-excursion + (save-restriction + (save-match-data + (progn + (re-search-backward "[^ \t\r\n]" nil t) + (re-search-forward "[ \t\r\n]+" nil t) + (replace-match "" nil nil)))))) + +(defun xe/how-many-region (begin end regexp &optional interactive) + "Print number of non-trivial matches for REGEXP in region. +Non-interactive arguments are Begin End Regexp" + (interactive "r\nsHow many matches for (regexp): \np") + (let ((count 0) opoint) + (save-excursion + (setq end (or end (point-max))) + (goto-char (or begin (point))) + (while (and (< (setq opoint (point)) end) + (re-search-forward regexp end t)) + (if (= opoint (point)) + (forward-char 1) + (setq count (1+ count)))) + (if interactive (message "%d occurrences" count)) + count))) + +(defun xe/linum-format-func (line) + "Properly format the line number" + (let ((w (length (number-to-string (count-lines (point-min) (point-max)))))) + (propertize (format (format " %%%dd " w) line) 'face 'linum))) + (provide 'xe-tools) ;;; xe-tools.el ends here