forked from emacs-evil/evil
-
Notifications
You must be signed in to change notification settings - Fork 0
/
evil-command-window.el
189 lines (165 loc) · 7.83 KB
/
evil-command-window.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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
;;; evil-command-window.el --- Evil command line window implementation -*- lexical-binding: t -*-
;; Author: Emanuel Evans <emanuel.evans at gmail.com>
;; Maintainer: Vegard Øye <vegard_oye at hotmail.com>
;; Version: 1.14.0
;;
;; This file is NOT part of GNU Emacs.
;;; License:
;; This file is part of Evil.
;;
;; Evil 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.
;;
;; Evil 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 Evil. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
;; This provides an implementation of the vim command line window for
;; editing and repeating past ex commands and searches.
;;; Code:
(require 'evil-vars)
(require 'evil-common)
(require 'evil-search)
(require 'evil-ex)
(defvar evil-search-module)
(define-derived-mode evil-command-window-mode fundamental-mode "Evil-cmd"
"Major mode for the Evil command line window."
(auto-fill-mode 0)
(setq-local after-change-functions (cons 'evil-command-window-draw-prefix
after-change-functions)))
(defun evil-command-window (hist cmd-key execute-fn)
"Open a command line window for HIST with CMD-KEY and EXECUTE-FN.
HIST should be a list of commands. CMD-KEY should be the string of
the key whose history is being shown (one of \":\", \"/\", or
\"?\"). EXECUTE-FN should be a function of one argument to
execute on the result that the user selects."
(when (eq major-mode 'evil-command-window-mode)
(user-error "Cannot recursively open command line window"))
(dolist (win (window-list))
(when (equal (buffer-name (window-buffer win))
"*Command Line*")
(kill-buffer (window-buffer win))
(delete-window win)))
(split-window nil
(unless (zerop evil-command-window-height)
evil-command-window-height)
'above)
(setq evil-command-window-current-buffer (current-buffer))
(ignore-errors (kill-buffer "*Command Line*"))
(switch-to-buffer "*Command Line*")
(setq-local evil-command-window-execute-fn execute-fn)
(setq-local evil-command-window-cmd-key cmd-key)
(evil-command-window-mode)
(evil-command-window-insert-commands hist))
(defun evil-command-window-ex (&optional current-command execute-fn)
"Open a command line window for editing and executing ex commands.
If CURRENT-COMMAND is present, it will be inserted under the
cursor as the current command to be edited. If EXECUTE-FN is given,
it will be used as the function to execute instead of
`evil-command-window-ex-execute', the default."
(interactive)
(evil-command-window (cons (or current-command "") evil-ex-history)
":"
(or execute-fn 'evil-command-window-ex-execute)))
(defun evil-ex-command-window ()
"Start command window with ex history and current minibuffer content."
(interactive)
(let ((current (minibuffer-contents))
(config (current-window-configuration)))
(evil-ex-teardown)
(select-window (minibuffer-selected-window) t)
(evil-command-window-ex current (apply-partially 'evil-ex-command-window-execute config))))
(defun evil-ex-search-command-window ()
"Start command window with search history and current minibuffer content."
(interactive)
(let ((current (minibuffer-contents))
(config (current-window-configuration)))
(select-window (minibuffer-selected-window) t)
(evil-command-window (cons current evil-ex-search-history)
(evil-search-prompt (eq evil-ex-search-direction 'forward))
(apply-partially 'evil-ex-command-window-execute config))))
(defun evil-command-window-execute ()
"Execute the command under the cursor in the appropriate buffer.
The local var `evil-command-window-execute-fn' determines which
function to execute."
(interactive)
(let ((result (buffer-substring (line-beginning-position)
(line-end-position)))
(execute-fn evil-command-window-execute-fn)
(command-window (get-buffer-window)))
(select-window (previous-window))
(unless (equal evil-command-window-current-buffer (current-buffer))
(user-error "Originating buffer is no longer active"))
(kill-buffer "*Command Line*")
(delete-window command-window)
(funcall execute-fn result)
(setq evil-command-window-current-buffer nil)))
(defun evil-command-window-ex-execute (result)
"Execute RESULT as an ex command in the appropriate buffer."
(unless (string-match-p "^ *$" result)
(unless (equal result (car evil-ex-history))
(setq evil-ex-history (cons result evil-ex-history)))
(let ((evil-ex-current-buffer evil-command-window-current-buffer))
(evil-ex-execute result))))
(defun evil-command-window-search-forward ()
"Open a command line window for forward searches."
(interactive)
(evil-command-window (cons ""
(if (eq evil-search-module 'evil-search)
evil-ex-search-history
evil-search-forward-history))
"/"
(lambda (result)
(evil-command-window-search-execute result t))))
(defun evil-command-window-search-backward ()
"Open a command line window for backward searches."
(interactive)
(evil-command-window (cons ""
(if (eq evil-search-module 'evil-search)
evil-ex-search-history
evil-search-backward-history))
"?"
(lambda (result)
(evil-command-window-search-execute result nil))))
(defun evil-command-window-search-execute (result forward)
"Search for RESULT using FORWARD to determine direction."
(unless (zerop (length result))
(if (eq evil-search-module 'evil-search)
(progn
(setq evil-ex-search-pattern (evil-ex-make-search-pattern result)
evil-ex-search-direction (if forward 'forward 'backward))
(unless (equal result (car-safe evil-ex-search-history))
(push result evil-ex-search-history))
(evil-ex-search))
(if forward
(unless (equal result (car-safe evil-search-forward-history))
(push result evil-search-forward-history))
(unless (equal result (car-safe evil-search-backward-history))
(push result evil-search-backward-history)))
(evil-search result forward evil-regexp-search))))
(defun evil-command-window-draw-prefix (&rest ignored)
"Display `evil-command-window-cmd-key' as a prefix to the current line.
Parameters passed in through IGNORED are ignored."
(let ((prefix (propertize evil-command-window-cmd-key
'font-lock-face 'minibuffer-prompt)))
(set-text-properties (line-beginning-position) (line-beginning-position 2)
(list 'line-prefix prefix))))
(defun evil-command-window-insert-commands (hist)
"Insert the commands in HIST."
(let ((inhibit-modification-hooks t))
(mapc #'(lambda (cmd) (insert cmd) (newline)) hist)
(reverse-region (point-min) (point-max)))
(let ((prefix (propertize evil-command-window-cmd-key
'font-lock-face 'minibuffer-prompt)))
(set-text-properties (point-min) (point-max) (list 'line-prefix prefix)))
(goto-char (point-max))
(when (and (bolp) (not (bobp))) (backward-char))
(evil-adjust-cursor))
(provide 'evil-command-window)
;;; evil-command-window.el ends here