Equivalente a --no-wait for emacs

8

O emacsclientprograma permite um sinalizador --no-wait(abreviado como -n) que fará com que o servidor emacs visite o arquivo especificado e retorne imediatamente.

emacsclient -n ~/.bashrc

Se eu fornecer um editor alternativo, ele ainda funcionará nos casos em que não houver servidor Emacs em execução

emacsclient -n -a "/usr/local/bin/emacs" ~/.bashrc

No entanto, isso me dá um comportamento inconsistente, porque nos casos em que o servidor está sendo executado, essa chamada retornará imediatamente. Nos casos em que não há servidor em execução e o editor alternativo é usado, a chamada se torna uma chamada de bloqueio e não retornará até que eu saia do Emacs.

Existe uma maneira de dizer emacs(em oposição a emacsclient) para criar um novo quadro e depois retornar?

nispio
fonte
1
Parece que você está confortável em fornecer o Emacs como seu editor alternativo. Existe uma razão para você optar por não usar a opção -a ''"iniciar o daemon Emacs e tentar novamente o emacsclient"?
purple_arrows
@purple_arrows Na minha experiência, usar -a ''iniciará um daemon em vez de um servidor. Em seguida, ele tenta abrir um terminal Emacs, mas como eu forneci a -nopção, ele não fica aberto. Ele apenas volta para a concha.
Nispio 17/10/2014

Respostas:

6

Descrição

O comportamento padrão ao chamar o emacsclient é um pouco conservador. Confira este comentário no emacsclient.c :

  /* Unless we are certain we don't want to occupy the tty, send our
     tty information to Emacs.  For example, in daemon mode Emacs may
     need to occupy this tty if no other frame is available.  */

A partir de sua descrição e comentários, parece que você está tentando iniciar o servidor Emacs sob demanda enquanto também usa a -nsinalização. O comentário "por exemplo" aqui é por emacsclient -n -a '' FILEque não satisfaz o que você está procurando quando nenhum servidor está em execução.

  1. A -a ''lógica inicia um daemon.
  2. Depois, emacsclientele diz para criar um novo quadro de terminal, porque esse é o padrão, a menos que você esteja avaliando o elisp.
  3. A -nlógica mata imediatamente esse novo quadro de terminais.

Se você pudesse alterar a Etapa 2 para criar um novo quadro gráfico por padrão, emacsclient -n -a '' FILEfaça o que quiser.

Solução Elisp

Você pode fazer com que o Emacs crie um novo quadro gráfico por padrão, se você aconselhar a função da seguinte server-process-filtermaneira:

(defadvice server-process-filter (before prefer-graphical activate)
  ;; STRING is a sequence of commands sent from emacsclient to the server.
  (when (and
         ;; Check that we're editing a file, as opposed to evaluating elisp.
         (string-match "-file" string)
         ;; Check that there are no frames beyond the Emacs daemon's terminal.
         (daemonp)
         (null (cdr (frame-list)))
         (eq (selected-frame) terminal-frame)
         ;; Check that we have a graphical display.
         ;; `display-graphic-p' doesn't work here.
         (getenv "DISPLAY"))
    (setq string (concat
                  ;; STRING must be all one line, but comes to us
                  ;; newline-terminated.  Strip off the trailing newline.
                  (replace-regexp-in-string "\n$" "" string)
                  ;; Add the commands to create a graphical frame.
                  "-window-system "
                  "-display " (getenv "DISPLAY")
                  ;; Add back the newline.
                  "\n"))))

Coloque isso no seu arquivo init, então, como disse, emacsclient -n -a '' FILEe Bob é seu tio.

Compare com a Solução Shell

Por um lado, posso apontar algumas vantagens em usar essa abordagem de defadvice em comparação com o script sugerido por Archenoth

#!/bin/bash
emacs --eval '(server-start)' $* &

como o editor alternativo. Com o defadvice:

  1. save-buffers-kill-terminal( C-x C-cpor padrão) se comporta de maneira consistente em todos os quadros. Ele nunca mata o processo Emacs, porque cada quadro é sempre um quadro de cliente.
  2. O quadro terminal do daemon fica pendurado. Comandos como find-grepesse que são projetados para processos externos se comportam melhor quando o terminal burro está lá. Pelo menos, experimento menos dores de cabeça relacionadas à fuga de conchas.

Por outro lado ... sim.

  1. Esse script de shell é lindamente simples.
  2. Aconselhar o protocolo de comunicação do Emacs não é.

Conclusão

Talvez haja um compromisso? Este é o melhor que eu poderia inventar. Você o define como seu $ EDITOR.

#!/bin/sh

emacsclient -e "(frames-on-display-list \"${DISPLAY}\")" 1>/dev/null 2>/dev/null
if [ "$?" = "1" ]; then
    emacsclient -c -n -a "" "$@"
else
    emacsclient -n "$@"
fi
purple_arrows
fonte
Então, como aconselho uma função quando o emacs não está em execução?
Nispio 18/10/2014
Você deve poder simplesmente soltá-lo no arquivo init. O daemon lê esse arquivo quando é iniciado e termina a leitura antes que o emacsclient comece a enviar comandos. É assim que estou fazendo, pelo menos.
purple_arrows
4

Não tenho certeza de como fazer isso estritamente no Emacs, mas felizmente existem outras maneiras de obter o que você descreve.

Se você não tem algo .emacspara iniciar um servidor, sempre pode criar um pequeno script que inicie o Emacs com o arquivo que você deseja editar e inicie o servidor bifurcado.

Algo como:

#!/bin/bash
emacs --eval '(server-start)' $* &

E depois passe isso para -a.


No entanto ...
Se você tiver o servidor iniciado no seu .emacscomputador, não precisará criar um script; você tem uma opção um pouco mais concisa:

emacsclient -n -a "/usr/local/bin/emacs" ~/.bashrc &

O e comercial fará o segundo plano do processo e devolva instantaneamente o seu shell, mesmo quando o Emacs for iniciado pela primeira vez.

Pode ser necessário disowno processo se o bash matar trabalhos na saída. Se for esse o caso, basta adicionar disowna no final:

emacsclient -n -a "/usr/local/bin/emacs" ~/.bashrc & disown

No Windows, o equivalente mais próximo seria o startcomando " " ...

Portanto, como a sugestão de script acima, você provavelmente teria que criar um arquivo em lotes que contenha algo como:

start /b C:\path\to\emacs %*

E então aponte o -aargumento para ele.
Isso deve executar o arquivo em lotes e retornar imediatamente após iniciar o Emacs com o arquivo apropriado.

Archenoth
fonte
Estou no Linux (RHEL 6.5) e &foi a primeira coisa que tentei. Infelizmente, o texto a seguir é enviado para stderr: e os blocos de terminais aguardando o término do processo: emacsclient: can't find socket; have you started the server? To start the server in Emacs, type "M-x server-start". Acho que os emacsclientgarfos estão em segundo plano, mas ele invoca o emacsque é aberto em primeiro plano.
Nispio 17/10/2014
Nesse caso, talvez um pequeno script possa ser a melhor rota ..? Algo como emacs --eval '(server-start)' $* &talvez? Dessa forma, o servidor inicia, você obtém seu terminal e emacsclientpossui um servidor ao qual pode se conectar.
Archenoth
Eu testei e adicionei à minha resposta ... Desculpe por isso! Eu tinha imaginado que você tinha um mecanismo para iniciar o servidor quando executava emacsda maneira normal. Me ocorre que a maioria das pessoas provavelmente não teria essa configuração, então essa é a primeira parte da resposta. Espero que ajude..!
Archenoth 17/10
O @nispio define seu parâmetro de editor alternativo para ter um & no final.
Malabarba 17/10/2014
2
@ Malabarba Você não pode passar argumentos de linha de comando ou diretivas de shell para o editor alternativo, e foi por isso que sugeri um pequeno script.
Archenoth 17/10