How does `C-x z` work?
Specifically, the keyboard event C-x
, following by N z
characters, will repeat the previous command N times.
I do not understand how this can work. As far as I understand, after the input event C-x z
, for the behavior to be as specified, Emacs would need to somehow remap the z
character to the command repeat
in order for the next z
to actually again execute `repeat'. Is this correct? If so, I do not understand how Emacs can change the keymap immediately after executing a command. If not, what is going on?
keymap commands
New contributor
add a comment |
Specifically, the keyboard event C-x
, following by N z
characters, will repeat the previous command N times.
I do not understand how this can work. As far as I understand, after the input event C-x z
, for the behavior to be as specified, Emacs would need to somehow remap the z
character to the command repeat
in order for the next z
to actually again execute `repeat'. Is this correct? If so, I do not understand how Emacs can change the keymap immediately after executing a command. If not, what is going on?
keymap commands
New contributor
add a comment |
Specifically, the keyboard event C-x
, following by N z
characters, will repeat the previous command N times.
I do not understand how this can work. As far as I understand, after the input event C-x z
, for the behavior to be as specified, Emacs would need to somehow remap the z
character to the command repeat
in order for the next z
to actually again execute `repeat'. Is this correct? If so, I do not understand how Emacs can change the keymap immediately after executing a command. If not, what is going on?
keymap commands
New contributor
Specifically, the keyboard event C-x
, following by N z
characters, will repeat the previous command N times.
I do not understand how this can work. As far as I understand, after the input event C-x z
, for the behavior to be as specified, Emacs would need to somehow remap the z
character to the command repeat
in order for the next z
to actually again execute `repeat'. Is this correct? If so, I do not understand how Emacs can change the keymap immediately after executing a command. If not, what is going on?
keymap commands
keymap commands
New contributor
New contributor
edited Jan 7 at 1:02
Drew
47.2k462104
47.2k462104
New contributor
asked Jan 7 at 0:48
extremeaxe5extremeaxe5
1211
1211
New contributor
New contributor
add a comment |
add a comment |
2 Answers
2
active
oldest
votes
The code is in repeat.el
. See command repeat
, which is what C-x z
is bound to.
The code uses the fact that Emacs records the current command and the last command in variables. The repeat
code resets the variable this-command
to what it records as the command that was previous to command repeat
.
Note that you can define your own repeatable command by using code such as this:
(defun my-repeat-command (command)
"Repeat COMMAND."
(require 'repeat)
(let ((repeat-previous-repeated-command command)
(repeat-message-function #'ignore)
(last-repeatable-command 'repeat))
(repeat nil)))
(defun some-command (...)
(interactive...)
...)
(defun some-command-repeat ()
"Invoke `some-command' in a repeatable way."
(interactive)
(my-repeat-command 'some-command))
repeat
does kind of "remap the key" on the fly. It uses set-transient-map
, defining the key in a transient map, and then it calls itself again.
Prior to Emacs 24 it didn't use a new (transient) keymap (such a thing didn't exist as such back then). It just checked whether the next key/command was the same as the last.
Essentially, repeat
fools Emacs into thinking that the current command is whatever command was used last.
1
Looking at the repeat defun, it also usesset-transient-map
to allow repeated taps of the last character in the binding to continue to repeat.
– glucas
Jan 7 at 1:46
@glucas: Yes. I edited the answer to be clearer about this. A transient map wasn't used originally. Using it is cleaner that what was done originally, but it's not a necessary part of the general approach behindrepeat
.
– Drew
Jan 7 at 5:17
add a comment |
As you guessed, for this to work, the repeat
command needs to be able to "change the keymap" immediately after executing a command. And indeed, repeat
ends with a call to set-transient-map
which makes a new keymap active (rather than modify in-place one of the currently active keymaps, it works by changing the set of active keymaps) with a binding for z
which shadows the normal binding of z
. This keymap needs to be short-lived, so set-transient-map
internally uses pre-command-hook
to deactivate that special keymap as soon as you hit something else than z
.
add a comment |
Your Answer
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "583"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
extremeaxe5 is a new contributor. Be nice, and check out our Code of Conduct.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2femacs.stackexchange.com%2fquestions%2f46948%2fhow-does-c-x-z-work%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
The code is in repeat.el
. See command repeat
, which is what C-x z
is bound to.
The code uses the fact that Emacs records the current command and the last command in variables. The repeat
code resets the variable this-command
to what it records as the command that was previous to command repeat
.
Note that you can define your own repeatable command by using code such as this:
(defun my-repeat-command (command)
"Repeat COMMAND."
(require 'repeat)
(let ((repeat-previous-repeated-command command)
(repeat-message-function #'ignore)
(last-repeatable-command 'repeat))
(repeat nil)))
(defun some-command (...)
(interactive...)
...)
(defun some-command-repeat ()
"Invoke `some-command' in a repeatable way."
(interactive)
(my-repeat-command 'some-command))
repeat
does kind of "remap the key" on the fly. It uses set-transient-map
, defining the key in a transient map, and then it calls itself again.
Prior to Emacs 24 it didn't use a new (transient) keymap (such a thing didn't exist as such back then). It just checked whether the next key/command was the same as the last.
Essentially, repeat
fools Emacs into thinking that the current command is whatever command was used last.
1
Looking at the repeat defun, it also usesset-transient-map
to allow repeated taps of the last character in the binding to continue to repeat.
– glucas
Jan 7 at 1:46
@glucas: Yes. I edited the answer to be clearer about this. A transient map wasn't used originally. Using it is cleaner that what was done originally, but it's not a necessary part of the general approach behindrepeat
.
– Drew
Jan 7 at 5:17
add a comment |
The code is in repeat.el
. See command repeat
, which is what C-x z
is bound to.
The code uses the fact that Emacs records the current command and the last command in variables. The repeat
code resets the variable this-command
to what it records as the command that was previous to command repeat
.
Note that you can define your own repeatable command by using code such as this:
(defun my-repeat-command (command)
"Repeat COMMAND."
(require 'repeat)
(let ((repeat-previous-repeated-command command)
(repeat-message-function #'ignore)
(last-repeatable-command 'repeat))
(repeat nil)))
(defun some-command (...)
(interactive...)
...)
(defun some-command-repeat ()
"Invoke `some-command' in a repeatable way."
(interactive)
(my-repeat-command 'some-command))
repeat
does kind of "remap the key" on the fly. It uses set-transient-map
, defining the key in a transient map, and then it calls itself again.
Prior to Emacs 24 it didn't use a new (transient) keymap (such a thing didn't exist as such back then). It just checked whether the next key/command was the same as the last.
Essentially, repeat
fools Emacs into thinking that the current command is whatever command was used last.
1
Looking at the repeat defun, it also usesset-transient-map
to allow repeated taps of the last character in the binding to continue to repeat.
– glucas
Jan 7 at 1:46
@glucas: Yes. I edited the answer to be clearer about this. A transient map wasn't used originally. Using it is cleaner that what was done originally, but it's not a necessary part of the general approach behindrepeat
.
– Drew
Jan 7 at 5:17
add a comment |
The code is in repeat.el
. See command repeat
, which is what C-x z
is bound to.
The code uses the fact that Emacs records the current command and the last command in variables. The repeat
code resets the variable this-command
to what it records as the command that was previous to command repeat
.
Note that you can define your own repeatable command by using code such as this:
(defun my-repeat-command (command)
"Repeat COMMAND."
(require 'repeat)
(let ((repeat-previous-repeated-command command)
(repeat-message-function #'ignore)
(last-repeatable-command 'repeat))
(repeat nil)))
(defun some-command (...)
(interactive...)
...)
(defun some-command-repeat ()
"Invoke `some-command' in a repeatable way."
(interactive)
(my-repeat-command 'some-command))
repeat
does kind of "remap the key" on the fly. It uses set-transient-map
, defining the key in a transient map, and then it calls itself again.
Prior to Emacs 24 it didn't use a new (transient) keymap (such a thing didn't exist as such back then). It just checked whether the next key/command was the same as the last.
Essentially, repeat
fools Emacs into thinking that the current command is whatever command was used last.
The code is in repeat.el
. See command repeat
, which is what C-x z
is bound to.
The code uses the fact that Emacs records the current command and the last command in variables. The repeat
code resets the variable this-command
to what it records as the command that was previous to command repeat
.
Note that you can define your own repeatable command by using code such as this:
(defun my-repeat-command (command)
"Repeat COMMAND."
(require 'repeat)
(let ((repeat-previous-repeated-command command)
(repeat-message-function #'ignore)
(last-repeatable-command 'repeat))
(repeat nil)))
(defun some-command (...)
(interactive...)
...)
(defun some-command-repeat ()
"Invoke `some-command' in a repeatable way."
(interactive)
(my-repeat-command 'some-command))
repeat
does kind of "remap the key" on the fly. It uses set-transient-map
, defining the key in a transient map, and then it calls itself again.
Prior to Emacs 24 it didn't use a new (transient) keymap (such a thing didn't exist as such back then). It just checked whether the next key/command was the same as the last.
Essentially, repeat
fools Emacs into thinking that the current command is whatever command was used last.
edited Jan 7 at 5:21
answered Jan 7 at 1:01
DrewDrew
47.2k462104
47.2k462104
1
Looking at the repeat defun, it also usesset-transient-map
to allow repeated taps of the last character in the binding to continue to repeat.
– glucas
Jan 7 at 1:46
@glucas: Yes. I edited the answer to be clearer about this. A transient map wasn't used originally. Using it is cleaner that what was done originally, but it's not a necessary part of the general approach behindrepeat
.
– Drew
Jan 7 at 5:17
add a comment |
1
Looking at the repeat defun, it also usesset-transient-map
to allow repeated taps of the last character in the binding to continue to repeat.
– glucas
Jan 7 at 1:46
@glucas: Yes. I edited the answer to be clearer about this. A transient map wasn't used originally. Using it is cleaner that what was done originally, but it's not a necessary part of the general approach behindrepeat
.
– Drew
Jan 7 at 5:17
1
1
Looking at the repeat defun, it also uses
set-transient-map
to allow repeated taps of the last character in the binding to continue to repeat.– glucas
Jan 7 at 1:46
Looking at the repeat defun, it also uses
set-transient-map
to allow repeated taps of the last character in the binding to continue to repeat.– glucas
Jan 7 at 1:46
@glucas: Yes. I edited the answer to be clearer about this. A transient map wasn't used originally. Using it is cleaner that what was done originally, but it's not a necessary part of the general approach behind
repeat
.– Drew
Jan 7 at 5:17
@glucas: Yes. I edited the answer to be clearer about this. A transient map wasn't used originally. Using it is cleaner that what was done originally, but it's not a necessary part of the general approach behind
repeat
.– Drew
Jan 7 at 5:17
add a comment |
As you guessed, for this to work, the repeat
command needs to be able to "change the keymap" immediately after executing a command. And indeed, repeat
ends with a call to set-transient-map
which makes a new keymap active (rather than modify in-place one of the currently active keymaps, it works by changing the set of active keymaps) with a binding for z
which shadows the normal binding of z
. This keymap needs to be short-lived, so set-transient-map
internally uses pre-command-hook
to deactivate that special keymap as soon as you hit something else than z
.
add a comment |
As you guessed, for this to work, the repeat
command needs to be able to "change the keymap" immediately after executing a command. And indeed, repeat
ends with a call to set-transient-map
which makes a new keymap active (rather than modify in-place one of the currently active keymaps, it works by changing the set of active keymaps) with a binding for z
which shadows the normal binding of z
. This keymap needs to be short-lived, so set-transient-map
internally uses pre-command-hook
to deactivate that special keymap as soon as you hit something else than z
.
add a comment |
As you guessed, for this to work, the repeat
command needs to be able to "change the keymap" immediately after executing a command. And indeed, repeat
ends with a call to set-transient-map
which makes a new keymap active (rather than modify in-place one of the currently active keymaps, it works by changing the set of active keymaps) with a binding for z
which shadows the normal binding of z
. This keymap needs to be short-lived, so set-transient-map
internally uses pre-command-hook
to deactivate that special keymap as soon as you hit something else than z
.
As you guessed, for this to work, the repeat
command needs to be able to "change the keymap" immediately after executing a command. And indeed, repeat
ends with a call to set-transient-map
which makes a new keymap active (rather than modify in-place one of the currently active keymaps, it works by changing the set of active keymaps) with a binding for z
which shadows the normal binding of z
. This keymap needs to be short-lived, so set-transient-map
internally uses pre-command-hook
to deactivate that special keymap as soon as you hit something else than z
.
answered Jan 7 at 3:39
StefanStefan
18.7k2461
18.7k2461
add a comment |
add a comment |
extremeaxe5 is a new contributor. Be nice, and check out our Code of Conduct.
extremeaxe5 is a new contributor. Be nice, and check out our Code of Conduct.
extremeaxe5 is a new contributor. Be nice, and check out our Code of Conduct.
extremeaxe5 is a new contributor. Be nice, and check out our Code of Conduct.
Thanks for contributing an answer to Emacs Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2femacs.stackexchange.com%2fquestions%2f46948%2fhow-does-c-x-z-work%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown