emacsclient window focus - emacs

How do I consistently control window focus after running emacsclient?
Currently, focus depends on if I already have an emacs server running. When emacsclient invokes an alternative editor, focus is shifted to the new emacs window. When emacsclient connects to an existing emacs server, focus is not shifted (ie. it stays on my putty client).
I would like to consistently focus on the emacs window, since I usually go to emacs after opening a file.
Any help would be greatly appreciated!
Notes
Version Info
emacs: 21.4.1
emacsclient: 21.4
client os: Windows XP Service Pack 3
x server: Exceed 11.0.0.0
Relevant section of my .bash_profile
# a wrapper is needed to sandwich multiple command line arguments in bash
# 2>/dev/null hides
# "emacsclient: can't find socket; have you started the server?"
emacs_wrapper () {
if [ 0 -eq $# ]
then
emacsclient -n -a emacs ~/notes.txt 2>/dev/null &
else
emacsclient -n -a emacs $* &
fi
}
alias x="emacs_wrapper"
Also, at the end of my .emacs I have
(server-start)
My current workaround is a simple autohotkey script, which focuses on my first Exceed window
^+x::
If WinExist("ahk_class EXCEEDW:MWCLIENT0")
WinActivate
return
As a side note, it seems my redirection to /dev/null confused the syntax-highlighter :(

How about:
emacsclient -e "(select-frame-set-input-focus (selected-frame))"
works for me on emacs 23.1
To unfocus (lower-frame) might be useful.

Would the "--create-frame" option to emacsclient work for you? You'd get a new frame for each file you opened this way, but at least it would be focused (I think).

For some unknown reason, the issue fixed itself. Opening files now consistently changes focus to the emacs frame with the corresponding file. I'm honestly unsure what changed the behavior, but I'm happy.
Thanks to everyone for their comments and suggestions!

Related

Can a command be send to VSCode, directly from the integrated terminal (integrated terminal -> VSCode API)?

Hi I would like to know whether one could call a VSCode command from the integrated terminal. So basically is the terminal aware of VSCode and can they communicate (at least from terminal => VSCode)
My Usecase: I would like to have H and L, to move to editor tab left / right of the terminal (I am using the terminal in an editor tab). Additionally, I would like that to happen when I am in vim normal mode in my zsh.
So I would like, when I am in normal mode and press H that the terminal sends an editor.tabNext (or whatever the command is) to VSCode.
I think I found a workaround at least. There is an extension called Remote Control (https://marketplace.visualstudio.com/items?itemName=eliostruyf.vscode-remote-control&ssr=false#review-details), with which I can send arbitrary commands to VSCode, so this seems to work. Proabably natively this is not possible, but maybe someone knows something.
EDIT1:
Here is my setup now:
if [ ! -z $VSCODE ]; then
_sendcmd() { echo "{ \"command\": \"workbench.action.$1\" }" | websocat ws://localhost:4242 }
# define commands and register them in zsh
editor_left() { _sendcmd previousEditor }; zle -N editor_left;
editor_right() { _sendcmd nextEditor }; zle -N editor_right;
bindkey -a H editor_left
bindkey -a L editor_right
fi
where $VSCODE is defined in VSCode through terminal.integrated.env = { "VSCODE": "1" }. May this make you as happy as it makes me happy.
Yes you can do this but it will require writing a simple extension and there is one flaw with it.
If you write a VSCode extension there is an API that will set environment variables in new terminals.
export function activate(context: ExtensionContext) {
...
context.environmentVariableCollection.replace("REMOTE_CONTROLL_EXTENSION_IPC_PATH", ipcPath);
What you do is create a Unix socket (or named pipe on Windows) and pass it into that environment variable. Then in your shell you can just send data to that socket.
This is much better than the approach used by the Remote Control extension that Dimfred mentioned - it's more secure and doesn't rely on known fixed ports, which means you're going to run into issues e.g. if they don't get closed properly or you run multiple copies of VSCode.
The only downside I've found with this approach is that if restart VSCode, then the socket will be closed but VSCode will try to restore shell sessions. Those shell sessions will be left with an old REMOTE_CONTROLL_EXTENSION_IPC_PATH value which points at a non-existent socket.
I'm not sure of a way around that yet.
Edit: Actually all you need to do is ensure your Unix socket path is tied to a workspace. At least this is what the built in Git extension does. See createIPCServer(). It uses storagePath which is specific to a workspace. It also unlinks the socket at that path (if any) when it starts.
I initially thought that might cause issues if you open the same workspace twice in two windows, but VSCode won't let you do that.

Emacsclient crashes when evaluating window functions

To not bore anyone here with specifics, whenever I evaluate an expression similar to this one:
emacsclient -t -e '(set-buffer *scratch*)'
the client will flash up on the terminal and crash.
This seems to be happening with all window-changing functions. Is the client not supposed to work like that? Running this in a normal emacs session does not cause this problem.
You're also using -t, but I'm not exactly sure why.
Is your emacs running in another tty session?
Or is your emacs running in windowing mode (e.g. on X Windows)?
If I have emacs running in windowing mode and I run the following command from another xterm window, then everything works exactly as I would expect it to:
emacsclient -c -e '(set-buffer "*scratch*")
Note in particular the -c option, and the fact that the buffer name is a string and so must be enclosed in double-quotes.

Emacsclient called by applescript can't find emacs server socket

The shell command
emacsclient -n -e '(make-remember-frame)'
works.
But the applescript
do shell script "emacsclient -n -e '(make-remember-frame)'"
just returns
emacsclient: can't find socket; have you started the server?
To start the server in Emacs, type \"M-x server-start\".
emacsclient: No socket or alternate editor. Please use:
--socket-name
--server-file (or environment variable EMACS_SERVER_FILE)
--alternate-editor (or environment variable ALTERNATE_EDITOR)
I rarely use this, but it has worked successfully in the past for various purposes. Perhaps you can modify it to suit your needs. The init.el or .emacs file must have (server-start) inside in order to make everything work. I have lots of stuff that loads when Emacs is activated for the first time, so I need a 5 second delay before emacsclient is called -- you can adjust the delay downward if your Emacs loads faster. If Emacs is already running, there is no need for a delay. You can comment out the verbal messages generated by say -- I used them this morning to test the conditions and make a minor adjustment to the script. The script contains a command-line example on line 4, which calls two Emacs functions. Of course, the path to your Emacs and emacsclient will need to be adjusted to wherever you have installed them on your computer.
# `(server-start)` must be inside `init.el` or `.emacs` file.
# This script can be used in the terimal: osascript path-to-script arguments
# Terminal Example:
# osascript /Users/HOME/.0.data/.0.emacs/.emacsclient.applescript "-e '(progn (dired \"/Applications\") (message \"Hello-World\!\"))'"
on run argv
set arg to item 1 of argv
set emacs to application "Emacs"
set appIsRunning to emacs is running
if appIsRunning then
say "Emacs is already running."
do shell script "/Users/HOME/.0.data/.0.emacs/Emacs_06_01_2014.app/Contents/MacOS/bin/emacsclient " & arg
else
tell application "/Users/HOME/.0.data/.0.emacs/Emacs_06_01_2014.app/Contents/MacOS/Emacs" to activate
say "Please wait five seconds for Emacs to load."
delay 5
do shell script "/Users/HOME/.0.data/.0.emacs/Emacs_06_01_2014.app/Contents/MacOS/bin/emacsclient " & arg
end if
end run

Closing emacs in emacs

Occasionally when using emacs in term mode I will mistakenly run emacs file instead of just opening the file. This will create a nested emacs client inside the current client. My problem is how to close the inner client only?
Answer
You should be able to C-z out of it, then kill it with
kill %1
Explanation
C-z will suspend the current process, assigning it a job number and returning you to the shell.
The jobs command will show you the current jobs and their numbers. kill allows you to kill a process by its job number using the %n syntax.
Just use the command M-x kill-emacs inside the inner emacs. Backgrounding and killing it works fine but it is a little bit more hackish.
You should use the top Emacs. Starts emacs with:
emacs --daemon
Starts all frame with:
emacsclient -c
From your term:
emacsclient -n
Or you should use eshell instead.

How can I make emacsclient just open a window for an existing emacs daemon without opening a new file

I use an emacs daemon to preserve my emacs session even if I have to reboot the machine that I run my X server on or if I want to access the same session from a different machine. This works very well but when restoring a session I'd quite like to just run "emacsclient --create-frame --no-wait" to connect to the daemon without opening a new file. It won't let me get away without specifying a filename.
I've tried using --eval to execute a function rather than open a file but the window just goes away when the evaluation is complete.
(Emacs 23.1 via backports on Debian GNU/Linux 5.0.)
From the help provided by emacsclient, you have a few options. First, is the one mentioned already which is emacsclient -c. That will try to create a frame associated with the emacs daemon. The advantage to this is that if DISPLAY is not set, then it will open emacs in the terminal.
Which brings us to the next best option (especially if you are logging in remotely): emacsclient -t which forces emacs to open up in terminal mode even if DISPLAY is set.
Also keep in mind that you can set the display from the command-line as well. I use this often when logging in remotely from VNC. The full command would be emacsclient -d DISPLAY -c
emacsclient -c works for me.
emacsclient -n -e "(make-frame)"
The -n flag means that the emacsclient doesn't wait, and the emacs instance doesn't destroy the frame.
If you are using emacs from the command line, you might also want to consider emacsclient -t