-
Notifications
You must be signed in to change notification settings - Fork 2
/
electric-cursor.el
143 lines (117 loc) · 5.13 KB
/
electric-cursor.el
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
;;; electric-cursor.el --- Change cursor automatically depending on mode -*- lexical-binding: t; -*-
;; Copyright (C) 2021 Case Duckworth
;; This file is NOT part of GNU Emacs.
;; Author: Case Duckworth <acdw@acdw.net>
;; License: ISC
;; SPDX-License-Identifier: ISC
;; Version: 0.2
;; Package-Requires: ((emacs "25.1"))
;; Keywords: terminals, frames
;; URL: https://github.com/duckwork/electric-cursor
;;; Commentary:
;; This package provides a global minor mode, `electric-cursor-mode', which
;; automatically changes the cursor depending on the active mode(s). The
;; precise modes and associated cursors can be customized with
;; `electric-cursor-alist', which maps modes with their respective cursors.
;; The default value of `electric-cursor-alist' maps `overwrite-mode' to 'block
;; and everything else to `bar'.
;;; Prior Art:
;; - https://github.com/ajsquared/bar-cursor/blob/master/bar-cursor.el
;;; Code:
(eval-when-compile
(require 'cl-lib))
;;; Variables
(defvar electric-cursor--original-cursor nil
"The cursor type before calling function `electric-cursor-mode'.")
;;; Customization options
(defgroup electric-cursor nil
"Customizations for electric cursor functionality."
:prefix "electric-cursor-"
:group 'cursor)
(defcustom electric-cursor-alist '((overwrite-mode . box)
(t . bar))
"Alist of modes and cursors to apply to them.
The car of each of element is a mode or hook, and the cdr is the
`cursor-type', which see."
:type '(alist :key-type (choice (function :tag "Mode")
(hook :tag "Mode hook"))
:value-type (get 'cursor-type 'custom-type)))
(defcustom electric-cursor-default-cursor (alist-get t electric-cursor-alist)
"The cursor to use when no modes in `electric-cursor-alist' are active.
This option is deprecated in favor of using a t car in
`electric-cursor-alist'."
:type (get 'cursor-type 'custom-type))
(defcustom electric-cursor-set-in-terminal t
"Should function `electric-cursor-mode' attempt to set cursor in a terminal?"
:type 'boolean)
;;; Internal functions
(defun electric-cursor--determine (&optional type)
"Determine the cursor that should be in use.
When TYPE is supplied, use that; otherwise, find the type from
`electric-cursor-alist' or `electric-cursor-default-cursor'."
(or type
(cl-loop for (mode . cursor) in electric-cursor-alist
if (or (eq mode t)
(and (boundp mode) (symbol-value mode)))
return cursor)
electric-cursor-default-cursor))
(defun electric-cursor--apply-to-hooks (fn)
"Apply FN to the modes defined in `electric-cursor-alist'."
(cl-loop for (mode-or-hook . _) in electric-cursor-alist
do (cond ((eq mode-or-hook t) nil)
((equal (substring (format "%s" mode-or-hook) -5) "-hook")
(funcall fn mode-or-hook #'electric-cursor-set-cursor))
(t (funcall fn (intern (format "%s-hook" mode-or-hook))
#'electric-cursor-set-cursor)))))
;;; Functions
(defun electric-cursor-set-terminal-cursor (&optional type)
"Set the cursor in a terminal.
Set it to TYPE if provided; otherwise, determine the cursor with
`electric-cursor--determine'."
(unless type (setq type (electric-cursor--determine)))
(when (and electric-cursor-set-in-terminal
(frame-parameter nil 'tty))
(send-string-to-terminal
(concat "\e["
(let ((n (pcase (or (car-safe type) type)
('box 2)
('bar 6)
('hbar 4)
(_ 0))))
(number-to-string (if blink-cursor-mode
(max (1- n) 0)
n)))
" q"))))
(defun electric-cursor-set-cursor (&optional type)
"Set the cursor.
When TYPE is non-nil, set the cursor to that; otherwise,
determine the cursor with `electric-cursor--determine'."
(let ((type (electric-cursor--determine type)))
(setq cursor-type type)
(electric-cursor-set-terminal-cursor type)))
(defun electric-cursor-add-hooks ()
"Add `electric-cursor-set-cursor' to modes in `electric-cursor-alist'."
(electric-cursor--apply-to-hooks #'add-hook))
(defun electric-cursor-remove-hooks ()
"Remove `electric-cursor-set-cursor' to modes in `electric-cursor-alist'."
(electric-cursor--apply-to-hooks #'remove-hook))
;;; Minor mode
;;;###autoload
(define-minor-mode electric-cursor-mode
"Change the cursor automatically depending on mode.
This global minor mode adds the necessary hooks to modes defined
in `electric-cursor-alist' to change the cursor's shape when
entering and exiting those modes. It also saves the cursor's
shape and restores it when exiting."
:lighter " |_"
:global t
(if electric-cursor-mode
(progn ; Enable
(setq electric-cursor--original-cursor cursor-type)
(electric-cursor-set-cursor)
(electric-cursor-add-hooks))
;; Disable
(electric-cursor-remove-hooks)
(electric-cursor-set-cursor electric-cursor--original-cursor)))
(provide 'electric-cursor)
;;; electric-cursor.el ends here