mirror of
https://codeberg.org/scip/viking-mode.git
synced 2025-12-16 20:10:59 +01:00
initial
This commit is contained in:
136
README.md
136
README.md
@@ -1,2 +1,138 @@
|
||||
# viking-mode
|
||||
Kill first, ask later - an emacs mode for killing things quickly
|
||||
|
||||
# Introduction
|
||||
|
||||
Viking minor mode enables you to delete things at point with one key
|
||||
stroke at once. More and more will be deleted if you repeat the key
|
||||
stroke.
|
||||
|
||||
The default key binding is C-d, but you may also bind it to C-k or
|
||||
whatever you wish.
|
||||
|
||||
If you press C-d the first time, the word at point will be deleted.
|
||||
If you press it again, the remainder of the line from point will be
|
||||
deleted. If pressed again, the whole line, then the paragraph and
|
||||
finally the whole buffer will be deleted.
|
||||
|
||||
Like:
|
||||
|
||||
[keep pressing ctrl] C-d - word
|
||||
C-d C-d - line remainder
|
||||
C-d C-d C-d - line
|
||||
C-d C-d C-d C-d - paragraph
|
||||
C-d C-d C-d C-d C-d - buffer
|
||||
|
||||
However, this only works when pressing the key in a row. If you do
|
||||
something else in between, it starts from scratch (i.e. delete word).
|
||||
|
||||
# Install
|
||||
|
||||
To use, save viking-mode.el to a directory in your load-path.
|
||||
|
||||
Add something like this to your config:
|
||||
|
||||
(require 'viking-mode)
|
||||
(add-hook 'text-mode-hook 'turn-on-viking-mode)
|
||||
|
||||
or load it manually
|
||||
|
||||
M-x viking-mode
|
||||
|
||||
However, it's also possible to enable viking-mode globally:
|
||||
|
||||
(viking-global-mode)
|
||||
|
||||
# Customize
|
||||
|
||||
By default viking-mode doesn't really delete things, everything
|
||||
remains available for yanking in the kill ring. However, you may turn
|
||||
it into berserk mode by setting 'viking-really-delete to t:
|
||||
|
||||
(setq viking-really-delete t)
|
||||
|
||||
In case you don't like the default key binding cascade, you may also
|
||||
use separate bindings for each kill function, e.g.:
|
||||
|
||||
(define-key viking-mode-map (kbd "C-d") nil) turn C-d into a prefix-key
|
||||
(define-key viking-mode-map (kbd "C-d w") 'vk/kill-word)
|
||||
(define-key viking-mode-map (kbd "C-d r") 'vk/kill-line-from-point)
|
||||
(define-key viking-mode-map (kbd "C-d l") 'vk/kill-line)
|
||||
(define-key viking-mode-map (kbd "C-d p") 'vk/kill-paragraph)
|
||||
(define-key viking-mode-map (kbd "C-d a") 'vk/kill-buffer)
|
||||
|
||||
Besides, the primary function of viking-mode is vk/last-key-repeats,
|
||||
which returns the number of times the last key have been pressed.
|
||||
This can be used for other things as well, for example:
|
||||
|
||||
(defun goto-begin()
|
||||
(interactive)
|
||||
(let* ((key-times (vk/last-key-repeats)))
|
||||
(cond
|
||||
((eq key-times 3)
|
||||
(if mark-active
|
||||
(goto-char (point-min))
|
||||
(beginning-of-buffer)))
|
||||
((eq key-times 2)
|
||||
(if mark-active () (push-mark))
|
||||
(move-to-window-line 0))
|
||||
((eq key-times 1)
|
||||
(beginning-of-line)))))
|
||||
|
||||
(defun goto-end ()
|
||||
(interactive)
|
||||
(let* ((key-times (vk/last-key-repeats)))
|
||||
(cond
|
||||
((eq key-times 3)
|
||||
(if mark-active
|
||||
(goto-char (point-max))
|
||||
(end-of-buffer)))
|
||||
((eq key-times 2)
|
||||
(if mark-active () (push-mark))
|
||||
(move-to-window-line -1)
|
||||
(end-of-line))
|
||||
((eq key-times 1)
|
||||
(end-of-line)))))
|
||||
|
||||
(global-set-key (kbd "<home>") 'goto-begin)
|
||||
(global-set-key (kbd "<end>") 'goto-end)
|
||||
|
||||
When you put this into your .emacs config, then you can do:
|
||||
|
||||
hit <home> once: goto beginning of current line
|
||||
repeat: goto beginning of current window
|
||||
repeat: goto beginning of current buffer
|
||||
|
||||
(and the same with <end> in the other direction)
|
||||
|
||||
|
||||
# Meta
|
||||
|
||||
Copyright (C) 2016, T.v.Dein <tlinden@cpan.org>
|
||||
|
||||
This file is NOT part of Emacs.
|
||||
|
||||
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 2 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
USA
|
||||
|
||||
Version: 0.01
|
||||
Author: T.v.Dein <tlinden@cpan.org>
|
||||
Maintainer: T.v.Dein <tlinden@cpan.org>
|
||||
Created: May 2016
|
||||
Keywords: kill delete
|
||||
Homepage: http://www.daemon.de/Viking
|
||||
Repository: https://github.com/tlinden/viking-mode
|
||||
License: GNU General Public License >= 2
|
||||
Distribution: This file is not part of Emacs
|
||||
|
||||
342
viking-mode.el
Normal file
342
viking-mode.el
Normal file
@@ -0,0 +1,342 @@
|
||||
;;; viking-mode.el - kill first, ask later
|
||||
|
||||
;; Copyright (C) 2016, T.v.Dein <tlinden@cpan.org>
|
||||
|
||||
;; This file is NOT part of Emacs.
|
||||
|
||||
;; 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 2 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 this program; if not, write to the Free Software
|
||||
;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
;; USA
|
||||
|
||||
;; Version: 0.01
|
||||
;; Author: T.v.Dein <tlinden@cpan.org>
|
||||
;; Maintainer: T.v.Dein <tlinden@cpan.org>
|
||||
;; Created: May 2016
|
||||
;; Keywords: kill delete
|
||||
;; Homepage: http://www.daemon.de/Viking
|
||||
;; Repository: https://github.com/tlinden/viking-mode
|
||||
;; License: GNU General Public License >= 2
|
||||
;; Distribution: This file is not part of Emacs
|
||||
|
||||
;;; Commentary
|
||||
|
||||
;; Viking minor mode enables you to delete things at point with one
|
||||
;; key stroke at once. More and more will be deleted if you repeat the
|
||||
;; key stroke.
|
||||
|
||||
;; The default key binding is C-d, but you may also bind it to C-k or
|
||||
;; whatever you wish.
|
||||
|
||||
;; If you press C-d the first time, the word at point will be deleted.
|
||||
;; If you press it again, the remainder of the line from point will be
|
||||
;; deleted. If pressed again, the whole line, then the paragraph and
|
||||
;; finally the whole buffer will be deleted.
|
||||
|
||||
;; Like:
|
||||
;; [keep pressing ctrl] C-d - word
|
||||
;; C-d C-d - line remainder
|
||||
;; C-d C-d C-d - line
|
||||
;; C-d C-d C-d C-d - paragraph
|
||||
;; C-d C-d C-d C-d C-d - buffer
|
||||
|
||||
;; However, this only works when pressing the key in a row. If you do
|
||||
;; something else in between, it starts from scratch (i.e. delete
|
||||
;; word).
|
||||
|
||||
;; To use, save viking-mode.el to a directory in your load-path.
|
||||
|
||||
;; Add something like this to your config:
|
||||
|
||||
;; (require 'viking-mode)
|
||||
;; (add-hook 'text-mode-hook 'turn-on-viking-mode)
|
||||
|
||||
;; or load it manually
|
||||
|
||||
;; M-x viking-mode
|
||||
|
||||
;; However, it's also possible to enable viking-mode globally:
|
||||
|
||||
;; (viking-global-mode)
|
||||
|
||||
;; By default viking-mode doesn't really delete things, everything
|
||||
;; remains available for yanking in the kill ring. However, you may
|
||||
;; turn it into berserk mode by setting 'viking-really-delete to t:
|
||||
|
||||
;; (setq viking-really-delete t)
|
||||
|
||||
;; In case you don't like the default key binding cascade, you may
|
||||
;; also use separate bindings for each kill function, e.g.:
|
||||
|
||||
;; (define-key viking-mode-map (kbd "C-d") nil) ;; turn C-d into a prefix-key
|
||||
;; (define-key viking-mode-map (kbd "C-d w") 'vk/kill-word)
|
||||
;; (define-key viking-mode-map (kbd "C-d r") 'vk/kill-line-from-point)
|
||||
;; (define-key viking-mode-map (kbd "C-d l") 'vk/kill-line)
|
||||
;; (define-key viking-mode-map (kbd "C-d p") 'vk/kill-paragraph)
|
||||
;; (define-key viking-mode-map (kbd "C-d a") 'vk/kill-buffer)
|
||||
|
||||
;; Besides, the primary function of viking-mode is vk/last-key-repeats,
|
||||
;; which returns the number of times the last key have been pressed.
|
||||
;; This can be used for other things as well, for example:
|
||||
|
||||
;; (defun goto-begin()
|
||||
;; (interactive)
|
||||
;; (let* ((key-times (vk/last-key-repeats)))
|
||||
;; (cond
|
||||
;; ((eq key-times 3)
|
||||
;; (if mark-active
|
||||
;; (goto-char (point-min))
|
||||
;; (beginning-of-buffer)))
|
||||
;; ((eq key-times 2)
|
||||
;; (if mark-active () (push-mark))
|
||||
;; (move-to-window-line 0))
|
||||
;; ((eq key-times 1)
|
||||
;; (beginning-of-line)))))
|
||||
|
||||
;; (defun goto-end ()
|
||||
;; (interactive)
|
||||
;; (let* ((key-times (vk/last-key-repeats)))
|
||||
;; (cond
|
||||
;; ((eq key-times 3)
|
||||
;; (if mark-active
|
||||
;; (goto-char (point-max))
|
||||
;; (end-of-buffer)))
|
||||
;; ((eq key-times 2)
|
||||
;; (if mark-active () (push-mark))
|
||||
;; (move-to-window-line -1)
|
||||
;; (end-of-line))
|
||||
;; ((eq key-times 1)
|
||||
;; (end-of-line)))))
|
||||
|
||||
;; (global-set-key (kbd "<home>") 'goto-begin)
|
||||
;; (global-set-key (kbd "<end>") 'goto-end)
|
||||
|
||||
;; When you put this into your .emacs config, then you can do:
|
||||
;; hit <home> once: goto beginning of current line
|
||||
;; repeat: goto beginning of current window
|
||||
;; repeat: goto beginning of current buffer
|
||||
;; (and the same with <end> in the other direction)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
;;; Code
|
||||
;;;; Customizable variables
|
||||
;;;;; Fonts
|
||||
|
||||
(defface viking-blink
|
||||
'((t :inherit highlight))
|
||||
"Level 1."
|
||||
:group 'viking-mode)
|
||||
|
||||
;;;;; Modify behavior
|
||||
|
||||
(defcustom viking-blink-time 0.2
|
||||
"How long should 'vk/blink-region highligh a region,
|
||||
in seconds, specify milliseconds like this: 0.1"
|
||||
:group 'viking-mode)
|
||||
|
||||
(defcustom viking-really-delete nil
|
||||
"If set to t, really delete killed things. That is,
|
||||
nothing will remain available via kill-ring once deleted.
|
||||
The default is nil: keep deleted things in the kill-ring."
|
||||
:group 'viking-mode)
|
||||
|
||||
|
||||
|
||||
;;;; Functions
|
||||
;;;;; Utilities
|
||||
|
||||
;; internal utility functions required by the kill functions
|
||||
|
||||
(defun vk/blink-region(begin end)
|
||||
"Blink a region shortly. It does this by highlighting the
|
||||
region between 'begin and 'end using 'font-lock-viking-face
|
||||
for 'viking-blink-time seconds."
|
||||
(interactive)
|
||||
(let* ((rh (make-overlay begin end)))
|
||||
(progn
|
||||
(overlay-put rh 'face 'viking-blink)
|
||||
(sit-for viking-blink-time t)
|
||||
(delete-overlay rh)
|
||||
)))
|
||||
|
||||
(defun vk/get-point (symbol &optional arg)
|
||||
"Returns the point by evaluating 'symbol, which
|
||||
should be a point-moving function."
|
||||
(funcall symbol arg)
|
||||
(point)
|
||||
)
|
||||
|
||||
(defun vk/last-key-repeats ()
|
||||
"Returns how many times the last key has been pressed as integer."
|
||||
;; FIXME: should be possible with just counting '(recent-keys)
|
||||
(interactive)
|
||||
(let* ((keys (recent-keys))
|
||||
(len (length keys))
|
||||
(key1 (if (> len 0) (elt keys (- len 1)) nil))
|
||||
(key2 (if (> len 1) (elt keys (- len 2)) nil))
|
||||
(key3 (if (> len 2) (elt keys (- len 3)) nil))
|
||||
(key4 (if (> len 3) (elt keys (- len 4)) nil))
|
||||
(key5 (if (> len 4) (elt keys (- len 5)) nil))
|
||||
(key-equal-1 (equal key1 key2))
|
||||
(key-equal-2 (and key-equal-1 (equal key2 key3)))
|
||||
(key-equal-3 (and key-equal-2 (equal key3 key4)))
|
||||
(key-equal-4 (and key-equal-3 (equal key4 key5))))
|
||||
(cond (key-equal-4 5)
|
||||
(key-equal-3 4)
|
||||
(key-equal-2 3)
|
||||
(key-equal-1 2)
|
||||
(t 1)
|
||||
)))
|
||||
|
||||
;;;;; kill/delete wrappers
|
||||
|
||||
(defun vk/kill-region (beg end)
|
||||
"Deletes or kills a region depending on 'viking-really-delete."
|
||||
(message "vkkill")
|
||||
(if viking-really-delete
|
||||
(delete-region beg end)
|
||||
(kill-region beg end)))
|
||||
|
||||
(defun vk/really-delete-line () ;; based on code by xah
|
||||
"kill-line without copy"
|
||||
(interactive)
|
||||
(delete-region
|
||||
(point)
|
||||
(save-excursion (move-end-of-line 1) (point)))
|
||||
(delete-char 1)
|
||||
)
|
||||
|
||||
;;;;; Interactive kill functions
|
||||
|
||||
(defun vk/kill-word-at-point ()
|
||||
"Kill word at point."
|
||||
(interactive)
|
||||
(let
|
||||
((beg (vk/get-point 'backward-word 1))
|
||||
(end (vk/get-point 'forward-word 1)))
|
||||
(progn
|
||||
(vk/blink-region beg end)
|
||||
(vk/kill-region beg end)
|
||||
(message "word at point deleted"))))
|
||||
|
||||
|
||||
(defun vk/kill-word-right ()
|
||||
"Kill word to the right"
|
||||
(interactive)
|
||||
(let
|
||||
((beg (point))
|
||||
(end (vk/get-point 'forward-word 1)))
|
||||
(vk/blink-region beg end)
|
||||
(vk/kill-region beg end)
|
||||
(message "word right of point deleted")))
|
||||
|
||||
(defun vk/kill-word ()
|
||||
"Kill word"
|
||||
(interactive)
|
||||
(if (eq (point) (line-beginning-position))
|
||||
(vk/kill-word-right)
|
||||
(vk/kill-word-at-point)
|
||||
))
|
||||
|
||||
(defun vk/kill-line ()
|
||||
"Kill line at point including newline."
|
||||
(interactive)
|
||||
(vk/blink-region (vk/get-point 'beginning-of-line 1) (vk/get-point 'end-of-line 1))
|
||||
(move-beginning-of-line 1)
|
||||
(let ((k kill-whole-line))
|
||||
(progn
|
||||
(setq kill-whole-line t) ;; temp enable
|
||||
(if viking-really-delete
|
||||
(vk/really-delete-line)
|
||||
(kill-line)
|
||||
)
|
||||
(setq kill-whole-line k)
|
||||
))
|
||||
(message "line at point deleted"))
|
||||
|
||||
(defun vk/kill-line-from-point ()
|
||||
"Kill line from point to the right without newline."
|
||||
(interactive)
|
||||
(let ((beg (point))
|
||||
(end (vk/get-point 'end-of-line 1)))
|
||||
(progn
|
||||
(vk/blink-region beg end)
|
||||
(vk/kill-region beg end)
|
||||
(message "line from point deleted"))))
|
||||
|
||||
(defun vk/kill-paragraph ()
|
||||
"Kill paragraph at point."
|
||||
(interactive)
|
||||
(let
|
||||
((beg (vk/get-point 'backward-paragraph 1))
|
||||
(end (vk/get-point 'forward-paragraph 1)))
|
||||
(progn
|
||||
(vk/blink-region beg end)
|
||||
(vk/kill-region beg end)
|
||||
(message "paragraph at point deleted"))))
|
||||
|
||||
(defun vk/kill-buffer ()
|
||||
"Kill the whole buffer."
|
||||
(interactive)
|
||||
(let ((beg (point-min))
|
||||
(end (point-max)))
|
||||
(progn
|
||||
(vk/blink-region beg end)
|
||||
(vk/kill-region beg end)
|
||||
(message "buffer deleted"))))
|
||||
|
||||
;;;;; Primary key binding function
|
||||
|
||||
(defun vk/kill-thing-at-point()
|
||||
"Delete thing at point. Checks how many times the
|
||||
calling key has been pressed and runs the appropriate
|
||||
kill function then."
|
||||
(interactive)
|
||||
(let* ((key-times (vk/last-key-repeats)))
|
||||
(cond
|
||||
((eq key-times 5) (vk/kill-buffer))
|
||||
((eq key-times 4) (vk/kill-paragraph))
|
||||
((eq key-times 3) (vk/kill-line))
|
||||
((eq key-times 2) (vk/kill-line-from-point))
|
||||
((eq key-times 1) (vk/kill-word))
|
||||
)
|
||||
))
|
||||
|
||||
;;;; Interface
|
||||
;;;###autoload
|
||||
|
||||
;; the minor mode, can be enabled by major mode via hook or manually
|
||||
(define-minor-mode viking-mode "kill first, ask later"
|
||||
:lighter " V"
|
||||
:group 'viking-mode
|
||||
:keymap (let ((map (make-sparse-keymap)))
|
||||
(define-key map (kbd "C-d") 'vk/kill-thing-at-point)
|
||||
map))
|
||||
|
||||
;; just in case someone wants to use it globally
|
||||
(define-global-minor-mode viking-global-mode
|
||||
viking-mode
|
||||
(lambda () (viking-mode t)
|
||||
))
|
||||
|
||||
;; be nice and provide a toggle
|
||||
(defun turn-on-viking-mode ()
|
||||
"turn viking-mode on"
|
||||
(interactive)
|
||||
(viking-mode 1))
|
||||
|
||||
;; un-*ing-believable: I'm done *g*
|
||||
(provide 'viking-mode)
|
||||
Reference in New Issue
Block a user