[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[nongnu] elpa/crux 12c4901 001/112: Initial commit
From: |
ELPA Syncer |
Subject: |
[nongnu] elpa/crux 12c4901 001/112: Initial commit |
Date: |
Wed, 11 Aug 2021 09:57:42 -0400 (EDT) |
branch: elpa/crux
commit 12c4901d85813a5308767fda5d46507e7ce68078
Author: Bozhidar Batsov <bozhidar@batsov.com>
Commit: Bozhidar Batsov <bozhidar@batsov.com>
Initial commit
---
README.md | 85 ++++++++++++++
crux.el | 373 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 458 insertions(+)
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..d64dc89
--- /dev/null
+++ b/README.md
@@ -0,0 +1,85 @@
+[![License GPL 3][badge-license]][copying]
+[![MELPA][melpa-badge]][melpa-package]
+[![MELPA Stable][melpa-stable-badge]][melpa-stable-package]
+
+# crux
+
+A **C**ollection of **R**idiculously **U**seful e**X**tensions for Emacs.
+crux bundles a few useful interactive commands to enhance your
+overall Emacs experience.
+
+## Installation
+
+Available on all major `package.el` community maintained repos -
+[MELPA Stable][] and [MELPA][] repos.
+
+MELPA Stable is recommended as it has the latest stable version.
+MELPA has a development snapshot for users who don't mind breakage but
+don't want to run from a git checkout.
+
+You can install `crux` using the following command:
+
+<kbd>M-x package-install [RET] crux [RET]</kbd>
+
+or if you'd rather keep it in your dotfiles:
+
+```el
+(unless (package-installed-p 'crux)
+ (package-refresh-contents)
+ (package-install 'crux))
+```
+
+If the installation doesn't work try refreshing the package list:
+
+<kbd>M-x package-refresh-contents</kbd>
+
+Add the following to your Emacs config to enable
+`crux`:
+
+```el
+(crux-setup-default-keybindings)
+```
+
+## Keybindings
+
+Here's the list of the default keybindings. Feel free to bind
+individual commands to whatever keybindings you prefer.
+
+Keybinding | Description
+-------------------|------------------------------------------------------------
+<kbd>C-c o</kbd> | Open the currently visited file with an external program.
+<kbd>C-S-RET</kbd> or <kbd>Super-o</kbd> | Insert an empty line above the
current line and indent it properly.
+<kbd>S-RET</kbd> or <kbd>M-o</kbd> | Insert an empty line and indent it
properly (as in most IDEs).
+<kbd>C-c n</kbd> | Fix indentation in buffer and strip whitespace.
+<kbd>C-c f</kbd> | Open recently visited file.
+<kbd>C-M-\\</kbd> | Indent region (if selected) or the entire buffer.
+<kbd>C-c u</kbd> | Open a new buffer containing the contents of URL.
+<kbd>C-c e</kbd> | Eval a bit of Emacs Lisp code and replace it with its
result.
+<kbd>C-c s</kbd> | Swap two active windows.
+<kbd>C-c D</kbd> | Delete current file and buffer.
+<kbd>C-c r</kbd> | Rename the current buffer and its visiting file if any.
+<kbd>C-c t</kbd> | Open a terminal emulator (`ansi-term`).
+<kbd>C-c k</kbd> | Kill all open buffers except the one you're currently in.
+<kbd>C-c TAB</kbd> | Indent and copy region to clipboard
+<kbd>C-c I</kbd> | Open user's init file.
+<kbd>C-c S</kbd> | Open shell's init file.
+<kbd>Super-r</kbd> | Recent files
+<kbd>Super-j</kbd> | Join lines
+<kbd>Super-k</kbd> | Kill whole line
+<kbd>C-Backspace</kbd> | Kill line backwards
+
+## License
+
+Copyright © 2015 Bozhidar Batsov and [contributors][].
+
+Distributed under the GNU General Public License; type <kbd>C-h C-c</kbd> to
view it.
+
+[badge-license]: https://img.shields.io/badge/license-GPL_3-green.svg
+[melpa-badge]: http://melpa.org/packages/crux-badge.svg
+[melpa-stable-badge]: http://stable.melpa.org/packages/crux-badge.svg
+[melpa-package]: http://melpa.org/#/crux
+[melpa-stable-package]: http://stable.melpa.org/#/crux
+[COPYING]: http://www.gnu.org/copyleft/gpl.html
+[contributors]: https://github.com/clojure-emacs/crux/contributors
+[melpa]: http://melpa.org
+[melpa stable]: http://stable.melpa.org
diff --git a/crux.el b/crux.el
new file mode 100644
index 0000000..95b299a
--- /dev/null
+++ b/crux.el
@@ -0,0 +1,373 @@
+;;; crux --- A Collection of Ridiculously Useful eXtensions.
+;;
+;; Copyright © 2015 Bozhidar Batsov
+;;
+;; Author: Bozhidar Batsov <bozhidar@batsov.com>
+;; URL: https://github.com/bbatsov/crux
+;; Version: 0.1.0
+;; Keywords: convenience
+;; Package-Requires: ((seq "1.11"))
+
+;; This file is not part of GNU Emacs.
+
+;;; Commentary:
+
+;; A cornucopia of useful interactive commands to make your Emacs
+;; experience more enjoyable.
+
+;;; License:
+
+;; This program is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License
+;; as published by the Free Software Foundation; either version 3
+;; of the License, or (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING. If not, write to the
+;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
+
+;;; Code:
+
+(require 'thingatpt)
+(require 'seq)
+
+(defun crux-open-with (arg)
+ "Open visited file in default external program.
+When in dired mode, open file under the cursor.
+
+With a prefix ARG always prompt for command to use."
+ (interactive "P")
+ (let* ((current-file-name
+ (if (eq major-mode 'dired-mode)
+ (dired-get-file-for-visit)
+ buffer-file-name))
+ (open (pcase system-type
+ (`darwin "open")
+ ((or `gnu `gnu/linux `gnu/kfreebsd) "xdg-open")))
+ (program (if (or arg (not open))
+ (read-shell-command "Open current file with: ")
+ open)))
+ (start-process "crux-open-with-process" nil program current-file-name)))
+
+(defun crux-buffer-mode (buffer-or-name)
+ "Retrieve the `major-mode' of BUFFER-OR-NAME."
+ (with-current-buffer buffer-or-name
+ major-mode))
+
+(defvar crux-term-buffer-name "ansi"
+ "The default `ansi-term' name used by `crux-visit-term-buffer'.
+This variable can be set via .dir-locals.el to provide multi-term support.")
+
+(defun crux-visit-term-buffer ()
+ "Create or visit a terminal buffer."
+ (interactive)
+ (crux-start-or-switch-to (lambda ()
+ (ansi-term crux-shell (concat
crux-term-buffer-name "-term")))
+ (format "*%s-term*" crux-term-buffer-name)))
+
+(defun crux-indent-rigidly-and-copy-to-clipboard (begin end arg)
+ "Indent region between BEGIN and END by ARG columns and copy to clipboard."
+ (interactive "r\nP")
+ (let ((arg (or arg 4))
+ (buffer (current-buffer)))
+ (with-temp-buffer
+ (insert-buffer-substring-no-properties buffer begin end)
+ (indent-rigidly (point-min) (point-max) arg)
+ (clipboard-kill-ring-save (point-min) (point-max)))))
+
+(defun crux-smart-open-line-above ()
+ "Insert an empty line above the current line.
+Position the cursor at it's beginning, according to the current mode."
+ (interactive)
+ (move-beginning-of-line nil)
+ (newline-and-indent)
+ (forward-line -1)
+ (indent-according-to-mode))
+
+(defun crux-smart-open-line (arg)
+ "Insert an empty line after the current line.
+Position the cursor at its beginning, according to the current mode.
+
+With a prefix ARG open line above the current line."
+ (interactive "P")
+ (if arg
+ (crux-smart-open-line-above)
+ (progn
+ (move-end-of-line nil)
+ (newline-and-indent))))
+
+(defun crux-top-join-line ()
+ "Join the current line with the line beneath it."
+ (interactive)
+ (delete-indentation 1))
+
+(defun crux-kill-whole-line (&optional arg)
+ "A simple wrapper around command `kill-whole-line' that respects indentation.
+Passes ARG to command `kill-whole-line' when provided."
+ (interactive "p")
+ (kill-whole-line arg)
+ (back-to-indentation))
+
+(defun crux-kill-like-backwards ()
+ "Kill line backwards and adjust the indentation."
+ (interactive)
+ (kill-line 0)
+ (indent-according-to-mode))
+
+(defun crux-move-beginning-of-line (arg)
+ "Move point back to indentation of beginning of line.
+
+Move point to the first non-whitespace character on this line.
+If point is already there, move to the beginning of the line.
+Effectively toggle between the first non-whitespace character and
+the beginning of the line.
+
+If ARG is not nil or 1, move forward ARG - 1 lines first. If
+point reaches the beginning or end of the buffer, stop there."
+ (interactive "^p")
+ (setq arg (or arg 1))
+
+ ;; Move lines first
+ (when (/= arg 1)
+ (let ((line-move-visual nil))
+ (forward-line (1- arg))))
+
+ (let ((orig-point (point)))
+ (back-to-indentation)
+ (when (= orig-point (point))
+ (move-beginning-of-line 1))))
+
+(defun crux-indent-defun ()
+ "Indent the current defun."
+ (interactive)
+ (save-excursion
+ (mark-defun)
+ (indent-region (region-beginning) (region-end))))
+
+(defun crux-get-positions-of-line-or-region ()
+ "Return positions (beg . end) of the current line
+or region."
+ (let (beg end)
+ (if (and mark-active (> (point) (mark)))
+ (exchange-point-and-mark))
+ (setq beg (line-beginning-position))
+ (if mark-active
+ (exchange-point-and-mark))
+ (setq end (line-end-position))
+ (cons beg end)))
+
+(defun crux-rename-buffer-and-file ()
+ "Rename current buffer and if the buffer is visiting a file, rename it too."
+ (interactive)
+ (let ((filename (buffer-file-name)))
+ (if (not (and filename (file-exists-p filename)))
+ (rename-buffer (read-from-minibuffer "New name: " (buffer-name)))
+ (let ((new-name (read-file-name "New name: " filename)))
+ (cond
+ ((vc-backend filename) (vc-rename-file filename new-name))
+ (t
+ (rename-file filename new-name t)
+ (set-visited-file-name new-name t t)))))))
+
+(defun crux-delete-file-and-buffer ()
+ "Kill the current buffer and deletes the file it is visiting."
+ (interactive)
+ (let ((filename (buffer-file-name)))
+ (when filename
+ (if (vc-backend filename)
+ (vc-delete-file filename)
+ (when (y-or-n-p (format "Are you sure you want to delete %s? "
filename))
+ (delete-file filename delete-by-moving-to-trash)
+ (message "Deleted file %s" filename)
+ (kill-buffer))))))
+
+(defun crux-view-url ()
+ "Open a new buffer containing the contents of URL."
+ (interactive)
+ (let* ((default (thing-at-point-url-at-point))
+ (url (read-from-minibuffer "URL: " default)))
+ (switch-to-buffer (url-retrieve-synchronously url))
+ (rename-buffer url t)
+ (goto-char (point-min))
+ (re-search-forward "^$")
+ (delete-region (point-min) (point))
+ (delete-blank-lines)
+ (set-auto-mode)))
+
+(defun crux-cleanup-buffer-or-region ()
+ "Cleanup a region if selected, otherwise the whole buffer."
+ (interactive)
+ (call-interactively 'untabify)
+ (unless (member major-mode crux-indent-sensitive-modes)
+ (call-interactively 'indent-region))
+ (whitespace-cleanup))
+
+(defun crux-eval-and-replace ()
+ "Replace the preceding sexp with its value."
+ (interactive)
+ (let ((value (eval (preceding-sexp))))
+ (backward-kill-sexp)
+ (insert (format "%s" value))))
+
+(defun crux-recompile-init ()
+ "Byte-compile all your dotfiles again."
+ (interactive)
+ (byte-recompile-directory crux-dir 0))
+
+(defun crux-file-owner-uid (filename)
+ "Return the UID of the FILENAME as an integer.
+
+See `file-attributes' for more info."
+ (nth 2 (file-attributes filename 'integer)))
+
+(defun crux-file-owned-by-user-p (filename)
+ "Return t if file FILENAME is owned by the currently logged in user."
+ (equal (crux-file-owner-uid filename)
+ (user-uid)))
+
+(defun crux-find-alternate-file-as-root (filename)
+ "Wraps `find-alternate-file' with opening a file as root."
+ (find-alternate-file (concat "/sudo:root@localhost:" filename)))
+
+(require 'ido)
+(defun crux-sudo-edit (&optional arg)
+ "Edit currently visited file as root.
+
+With a prefix ARG prompt for a file to visit.
+Will also prompt for a file to visit if current
+buffer is not visiting a file."
+ (interactive "P")
+ (if (or arg (not buffer-file-name))
+ (find-file (concat "/sudo:root@localhost:"
+ (ido-read-file-name "Find file(as root): ")))
+ (crux-find-alternate-file-as-root buffer-file-name)))
+
+(defun crux-reopen-as-root ()
+ "Find file as root if necessary."
+ (unless (or (tramp-tramp-file-p buffer-file-name)
+ (equal major-mode 'dired-mode)
+ (not (file-exists-p (file-name-directory buffer-file-name)))
+ (file-writable-p buffer-file-name)
+ (crux-file-owned-by-user-p buffer-file-name))
+ (crux-find-alternate-file-as-root buffer-file-name)))
+(add-hook 'find-file-hook 'crux-reopen-as-root)
+
+(defun crux-start-or-switch-to (function buffer-name)
+ "Invoke FUNCTION if there is no buffer with BUFFER-NAME.
+Otherwise switch to the buffer named BUFFER-NAME. Don't clobber
+the current buffer."
+ (if (not (get-buffer buffer-name))
+ (progn
+ (split-window-sensibly (selected-window))
+ (other-window 1)
+ (funcall function))
+ (switch-to-buffer-other-window buffer-name)))
+
+(defun crux-insert-date ()
+ "Insert a timestamp according to locale's date and time format."
+ (interactive)
+ (insert (format-time-string "%c" (current-time))))
+
+(defun crux-recentf-ido-find-file ()
+ "Find a recent file using ido."
+ (interactive)
+ (let ((file (ido-completing-read "Choose recent file: "
+ (mapcar #'abbreviate-file-name recentf-list)
+ nil t)))
+ (when file
+ (find-file file))))
+
+(defun crux-swap-windows ()
+ "If you have 2 windows, it swaps them."
+ (interactive)
+ (if (/= (count-windows) 2)
+ (message "You need exactly 2 windows to do this.")
+ (let* ((w1 (car (window-list)))
+ (w2 (cadr (window-list)))
+ (b1 (window-buffer w1))
+ (b2 (window-buffer w2))
+ (s1 (window-start w1))
+ (s2 (window-start w2)))
+ (set-window-buffer w1 b2)
+ (set-window-buffer w2 b1)
+ (set-window-start w1 s2)
+ (set-window-start w2 s1)))
+ (other-window 1))
+
+(defun crux-switch-to-previous-buffer ()
+ "Switch to previously open buffer.
+Repeated invocations toggle between the two most recently open buffers."
+ (interactive)
+ (switch-to-buffer (other-buffer (current-buffer) 1)))
+
+(defun crux-kill-other-buffers ()
+ "Kill all buffers but the current one.
+Doesn't mess with special buffers."
+ (interactive)
+ (when (y-or-n-p "Are you sure you want to kill all buffers but the current
one? ")
+ (seq-each
+ #'kill-buffer
+ (delete (current-buffer) (seq-filter #'buffer-file-name (buffer-list))))))
+
+(defun crux-create-scratch-buffer ()
+ "Create a new scratch buffer."
+ (interactive)
+ (let ((buf (generate-new-buffer "*scratch*")))
+ (switch-to-buffer buf)
+ (funcall initial-major-mode)))
+
+(defun crux-find-user-init-file ()
+ "Edit the `user-init-file', in another window."
+ (interactive "P")
+ (find-file-other-window user-init-file)
+ )
+
+(defun crux-find-shell-init-file ()
+ "Edit the shell init file in another window."
+ (interactive)
+ (let* ((shell (car (reverse (split-string (getenv "SHELL") "/" t))))
+ (shell-init-file (cond
+ ((string= "zsh" shell) ".zshrc")
+ ((string= "bash" shell) ".bashrc")
+ (t (error "Unknown shell")))))
+ (find-file-other-window (expand-file-name shell-init-file (getenv
"HOME")))))
+
+;;;###autoload
+(defun crux-setup-default-keybindings ()
+ "Set the recommended global keybindings for crux's commands."
+ (interactive)
+ (global-set-key [remap move-beginning-of-line] #'crux-move-beginning-of-line)
+ (global-set-key (kbd "C-c o") #'crux-open-with)
+ ;; mimic popular IDEs binding, note that it doesn't work in a terminal
session
+ (global-set-key [(shift return)] #'crux-smart-open-line)
+ (global-set-key (kbd "M-o") #'crux-smart-open-line)
+ (global-set-key [(control shift return)] #'crux-smart-open-line-above)
+ (global-set-key (kbd "C-c n") #'crux-cleanup-buffer-or-region)
+ (global-set-key (kbd "C-c f") #'crux-recentf-ido-find-file)
+ (global-set-key (kbd "C-M-z") #'crux-indent-defun)
+ (global-set-key (kbd "C-c u") #'crux-view-url)
+ (global-set-key (kbd "C-c e") #'crux-eval-and-replace)
+ (global-set-key (kbd "C-c s") #'crux-swap-windows)
+ (global-set-key (kbd "C-c D") #'crux-delete-file-and-buffer)
+ (global-set-key (kbd "C-c r") #'crux-rename-buffer-and-file)
+ (global-set-key (kbd "C-c t") #'crux-visit-term-buffer)
+ (global-set-key (kbd "C-c k") #'crux-kill-other-buffers)
+ (global-set-key (kbd "C-c TAB") #'crux-indent-rigidly-and-copy-to-clipboard)
+ (global-set-key (kbd "C-c I") #'crux-find-user-init-file)
+ (global-set-key (kbd "C-c S") #'crux-find-shell-init-file)
+ (global-set-key (kbd "s-r") #'crux-recentf-ido-find-file)
+ (global-set-key (kbd "s-j") #'crux-top-join-line)
+ (global-set-key (kbd "C-^") #'crux-top-join-line)
+ (global-set-key (kbd "s-k") #'crux-kill-whole-line)
+ (global-set-key (kbd "C-<backspace>" #'crux-kill-line-backwards))
+ (global-set-key (kbd "s-o") #'crux-smart-open-line-above)
+ (global-set-key [remap kill-whole-line] #'crux-kill-whole-line))
+
+(provide 'crux)
+;;; crux.el ends here
- [nongnu] branch elpa/crux created (now 6bfd212), ELPA Syncer, 2021/08/11
- [nongnu] elpa/crux 12c4901 001/112: Initial commit,
ELPA Syncer <=
- [nongnu] elpa/crux ae602a8 004/112: Use lexical scoping, ELPA Syncer, 2021/08/11
- [nongnu] elpa/crux 8666ae8 002/112: Fix a docstring, ELPA Syncer, 2021/08/11
- [nongnu] elpa/crux 51d4240 007/112: Add missing space, ELPA Syncer, 2021/08/11
- [nongnu] elpa/crux db47b78 010/112: Don't promote the default keybindings, ELPA Syncer, 2021/08/11
- [nongnu] elpa/crux 7d4e425 013/112: Add some example keybinding code, ELPA Syncer, 2021/08/11
- [nongnu] elpa/crux 9330468 016/112: Add missing crux-shell defcustom, ELPA Syncer, 2021/08/11
- [nongnu] elpa/crux c8ad7c1 017/112: Fix the interactive spec for crux-find-user-init-file, ELPA Syncer, 2021/08/11
- [nongnu] elpa/crux 61bf2bd 003/112: Code style, ELPA Syncer, 2021/08/11
- [nongnu] elpa/crux 66f4292 006/112: Code style, ELPA Syncer, 2021/08/11
- [nongnu] elpa/crux aafcf48 009/112: Introduce some customization options, ELPA Syncer, 2021/08/11