데몬 모드 : 시작시 대화식 프롬프트를 연기 하시겠습니까?


16

(반대로,이 질문은 데몬 모드에서 시작하고 대화식 대화 상자를 억제하는 방법 과 동일하지 않습니다 . 제출자에 의해 해당 질문에 "응답"되어 특정 프롬프트가 나타나는 원인을 제거했습니다.)

아직 존재하지 않는 미니 버퍼에 표시되는 프롬프트에 대한 응답을 영원히 기다리지 않는 일반적인 방법 이 있는지 알고 싶습니다 emacs --daemon.

Emacs가 시작 순서를 마칠 때까지 서버가 시작되지 않기 때문에이 프롬프트에 응답하기 위해 emacsclient에 연결할 수 없습니다. (이것은 ALTERNATE_EDITOR를 빈 문자열로 설정하여 emacsclient서버가 새 데몬을 시작할 수 없다는 것을 의미하면 여러 Emacs 데몬이 모두 멈추고 대기 할 수 있습니다.) killall emacs문제를 해결 해야합니다. 계속하기 전에.

(데몬 모드가 아닌 모드에서 Emacs를 시작하고 요청한 내용을 확인하여) 시작할 때 프롬프트를 표시하는 각각의 일로 whack-a-mole을 재생할 수 있지만 다음 데몬을 멈출 수 없기 때문에 해결책 이 아닙니다. 새로운 이유 때문에 스타트 업에 매달리지 않아도됩니다.

예를 들어 : 시스템 재부팅 또는 Emacs 크래시 이후 첫 번째 재부팅 후 Emacs가 기능 상실 Emacs에서 잠금 파일을 훔치는 것이 좋은지 알고 싶을 때 발생하는 일반적인 이유입니다. 프롬프트가 항상 "예"라고 상호 작용하지 않고 응답하도록 조언을 작성하여 문제를 해결할 수 있습니다. 그러나 이전 세션 저장에서 열린 파일 중 하나는 sudo 또는 SSH 비밀번호가 필요한 TRAMP 파일이므로 디먼이 비밀번호 프롬프트에서 대기 중입니다. 따라서 문제가 발생한 파일 을 제거하기 위해 세션 파일 ( vi또는 emacs -q!로)을 수동으로 편집하여 문제를 해결 하지만 다음 번에는 발생하지 않습니다.

따라서 시작시 세션 자동로드를 중지하고 첫 번째 emacsclient에서 수동으로 실행해야하는 명령으로 변경할 수 있습니다. 그러나 백그라운드에서 내 세션을로드하지 않으므로 사용할 준비가 될 때까지 준비가되면 데몬의 전체 목적이 손실됩니다!

그래서 내가 원하는 것은 :

  • (최상의) 나머지 초기화를 완료하면서 emacsclient를 열 때까지 미니 버퍼 프롬프트를 연기하는 방법.
  • (OK) 위의 설명과 같이 이미 조언하지 않은 모든 미니 버퍼 프롬프트를 만드는 방법 no은 emacsclient가 실행되고 있지 않으면 반환 됩니다. TRAMP 버퍼가 작동하는 한 오류가 발생하여 살 수 있습니다.

이러한 목표 중 하나를 달성 할 수있는 방법이 있습니까?


이러한 유형의 문제를 프로그래밍 방식으로 재현하여 커뮤니티에서 문제를 해결할 수있는 방법이 있습니까?
Melioratus

1
첫 번째 줄에 글을 썼을 때, 주어진 예 를 고치는 것은 매우 쉽습니다 . "의사, 내가 이렇게하면 아프다 ..." 문제는 일반적인 경우입니다. 그러나 문제를 만드는 간단한 방법은을 통해 시작 복원 데스크탑을 갖는 (read-desktop)다음 실행하기 전에 emacs --daemon정수를 .emacs.desktop.lock 에 넣어 가짜 잠금 파일을 만드는 것입니다 ( 불행히도 해당 파일 을 넣을 위치는 구성에 따라 다릅니다) 그러나 아마 당신의 homedir 또는 ~ / .emacs.d / 일 것 입니다
Trey

1
예를 들어 emacs.stackexchange.com/questions/8147/… 또는 emacs.stackexchange.com/questions/31621/… 과 같이 자주 언급되는 경우 입니다.
Trey

:이 버그는 관련 보인다 이맥스는 사용자와 상호 작용할 수 있는지 알려줄 수있는 방법 - 버그 # 13697를 하지만 아무도 내가 아는 한, 그것을 작동하지 않았다.
npostavs

@npostavs 링크에 감사드립니다 – 버그에 주석을 달았습니다. 알아 차리기 전에 여기에 댓글을 달았습니다 (삭제 된 이후).
Trey

답변:


2

우리가 논의한 바에 따르면, X-server를 실행하지 않으면 첫 번째 솔루션을 사용할 수 없게됩니다.

다음에서는 텍스트 터미널 프레임과 함께 작동하는 두 번째 솔루션을 제시합니다.

초기화시 하나를 통한 사용자 입력이 필요한 avoid-initial-terminal경우 텍스트 터미널 프레임을 열 때까지 Emacs에서 권장하는 기능이 대기합니다. 해당 프레임의 미니 버퍼에 프롬프트가 나타나고 대화 형 응답을 제공 할 수 있습니다.

코드 관련 정보는 코드에서 주석으로 제공됩니다. TODO자신의 구성을 삽입 할 위치를 나타내는 설명 이있는 마커가 있습니다. 현재 코드를 확인하는 테스트 양식이 있습니다.

;; TODO: Do here configure the server if needed.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Startup the server:
;; Analysis of read_from_minibuffer in src/minibuf.c and daemon_type in src/emacs.c
;; shows that daemon-initialized must have run before read-passwd / read-string
;; works on frames. Before it only works on stdin & stdout.
(server-start) ;;< early start
(let ((after-init-time before-init-time))
  (daemon-initialized)) ;; Finalize the daemon, 

(advice-add 'daemon-initialized :override #'ignore)
;;< Ignore `daemon-initialized' after initialization. It may only run once!
;; Now the background emacs is no longer marked as daemon. It just runs the server.

(defun prevent-server-start (&rest _ignore)
  "Prevent starting a server one time after `server-start' has been advised with this."
  (advice-remove 'server-start #'prevent-server-start))

(advice-add 'server-start :override #'prevent-server-start)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Prepare waiting for a real terminal frame when user input is required:

(defun avoid-initial-terminal (fun &rest args)
  "Wait until we are no longer on \"intial-terminal\".
Afterwards run `fun' with frame on the other terminal selected."
  (message "Avoiding initial terminal. Terminal: %S" (get-device-terminal nil))
  (while (string-equal
      (terminal-name (get-device-terminal nil))
      "initial_terminal")
    (sleep-for 1))
  ;; (message "Selected frame: %S; Running %S with %S." (selected-frame) fun args)
  (apply fun args))

(advice-add 'read-string :around #'avoid-initial-terminal)

(advice-add 'read-passwd :around #'avoid-initial-terminal)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; TODO: Your initialization that is not daemon related
;; and may require user input:

;; Currently this is just a test.
(read-passwd "Passwd: ")

(read-string "String: ")

(y-or-n-p "y-or-n query")

테스트 : 이맥스 버전 : 26.1

1) emacs --daemon콘솔에서 실행하십시오 .

2) emacsclient --tty다른 콘솔에서 실행하십시오 . 비밀번호와 문자열을 묻는 메시지가 표시됩니다. 그 후에는 y 또는 np 조회에 응답해야합니다.


3

정확히 당신이 요구하는 것이 아니라 원래 문제에 대한 해결책 일 수 있습니다.

emacs --daemon이 아직 존재하지 않는 미니 버퍼에 표시되는 프롬프트에 대한 응답을 영원히 기다리지 못하게하는 일반적인 방법이 있는지 알고 싶습니다.

데몬이 시작 단계에서 발생하는 질문에 대답하기위한 그래픽 프레임을 제공하면 더 이상 멈추지 않습니다.

아래 코드는 my-with-initial-frame사용 가능한 첫 번째 디스플레이 (예 :)에서 프레임을 여는 일반적인 조언 을 정의합니다 :0.0.

이 조언은 아래와 같이 y-or-n-p또는 과 같은 명령을 쿼리하는 데 쉽게 추가 할 수 있습니다 read-passwd.

프레임을 열면 사용자 인터페이스에서 쿼리에 응답 할 수있는 대략적인 가능성이 제공됩니다. 대화 상자를 사용할 수도 y-or-n-p있지만 특정 쿼리 명령에 대한 특수 솔루션이 필요합니다. 나는 그것을 피하고 싶었다.

init 파일에서 해당 코드를 시도하면 첫 번째 코드인지 확인하십시오.

(when (daemonp)

  (defun my-with-initial-frame (&rest _)
    "Ensure a frame on display :0.0 and ignore args."
    (let* ((display-list (x-display-list))
           (display-re (and display-list (regexp-opt display-list)))
           (term (and display-re (cl-some (lambda (term) (and (string-match display-re (terminal-name term)) term)) (terminal-list))))
           (frame (and term (cl-some (lambda (frame) (and (frame-live-p frame) frame)) (frames-on-display-list term)))))
      (select-frame (or frame (make-frame-on-display (getenv "DISPLAY"))))))

  (message "Advising querying functions with `my-with-initial-frame'.")
  (advice-add 'y-or-n-p :before #'my-with-initial-frame)
  (advice-add 'read-passwd :before #'my-with-initial-frame))

테스트:

가정 :

프로그램이 DISPLAY환경 변수 를 통해 연결할 수있는 실행중인 xserver가 있어야 합니다.

xterm에 입력 :

emacs --daemon

emacsclient --eval '(y-or-n-p "A")'

y-or-n-p쿼리 프롬프트 가있는 프레임이 열립니다 A (y or n). 해당 쿼리에 응답하고 다시 시도하십시오.

emacsclient --eval '(y-or-n-p "B")'

B (y or n)동일한 프레임에 프롬프트 가있는 새 쿼리 예를 들어 다음과 같이 해당 프레임을 닫고 C-x 5 0다시 시도하십시오.

emacsclient --eval '(y-or-n-p "C")'

쿼리 프롬프트와 함께 새 프레임이 열립니다 C (y or n).

암호 입력에서도 동일하게 작동합니다.


@Trey 내 코드에 실제로 문제가 있습니다 (실제로는 테스트에). x 서버를 처음 시작하면 작동하지 않았습니다. 데몬을 다시 시작하지 않았기 때문에 처음에는 알지 못했습니다. 나는 지금 그것을 고쳤다. 다시 테스트하십시오. 감사.
Tobias

내 Linux 가상에는 그래픽 터미널이 연결되어 있지 않으므로 실행할 수 없습니다 xterm. 또한이 솔루션이 작동하는 사람들에게는 효과가 없다고 생각합니다. 시작할 때 데몬을 실행하도록 설정 한 경우 로그인 화면 상단에 프레임을 열려고 시도 할 수 있으므로 허용되지 않습니다. 충돌합니다.
Trey

토비아스, 사과 만약 내 전화에 대답하고 자신이 짧은, 그래서 저를 정교하게 해보자 절단 할 수 있습니다 brusque- 소리 위 다음은 당신이 이상 데몬을 사용하여 실행하지 않는 무엇을 설명으로 볼 수있는 이점 server-start시작의 끝을 대신 클린 스타트 업이 발생하면 기다릴 필요가 없습니다. 그러나 ... 잘못 이해하지 않으면 GUI를 사용할 수 없으므로 Emacs 데몬을 시작하는 작업을 시스템 로그인 스크립트에 넣을 수 없기 때문에 기다려야합니다. (나와 같은 경우에는 결코 늦지 않을 것입니다.)
Trey

@Trey 채팅에 참여할 수 있습니까?
Tobias

1

나는 프롬프트를 연기 하는 것이 일반적으로 어려울 것이라고 생각 하지만, 그러한 프롬프트가 즉시 오류를 나타내도록 Emacs를 변경하는 것은 상당히 쉬워야합니다.

그뿐만 아니라 많은 체조가 없다면 그 프롬프트에 답할 수 없다면, 그것이 버그로 자격이 있다고 생각합니다. 그래서 버그 보고서를 제출하는 것이 좋습니다.


좀 더 자세히 설명해야한다고 생각합니다. 위의 현상금에 대한 의견에서 언급 한 데스크탑 저장 파일 잠금을 고려하십시오. 어떤 방식으로 "데스크톱"을 구체적으로 언급 하지 않고Warning: desktop file appears to be in use by PID xxx. Using it may cause conflicts. Use it anyway? (y or n) 프롬프트를 오류로 변경 하는 방법은 무엇입니까 (일반적이지 않기 때문에 whack-a-mole에 속함)?
Trey

스테판은 또한 귀찮게하지 않는 문제가있어 저를 밖으로 erroring :이 방법 데몬 이맥스를 실행하지 않기 때문에,하지만 일반적으로 유용한 답변이 해결해야 할 수 있도록 치명적으로하는 이맥스 다시 시작 systemd 또는 다른 감시자를 통해 기동의 원인이됩니다 루프에서. 그러나 오류를 무시하고 로그인 만하면 *Messages*첫 번째 클라이언트 연결에서 불충분 한 정보를 얻을 수 있으므로 사용자가 상태 저장 작업을 시도하기 전에 심각한 문제가 발생할 수 있으며 즉각적인주의가 필요합니다.
Trey

(을 통해 중, 데몬-경우 수동으로 시작할을 사용하지 않는 사람들을 위해 명확히하기 위해 emacs --daemon또는 시작하여 emacsclientALTERNATE_EDITOR빈 문자열로 환경 변수 설정, 당신은 일반적으로 이동하는 출력을 볼 수 *Messages*데몬 때까지 터미널에서 반향을 초기화가 완료되고 Emacs가 준비되었지만 많은 사람들이 Emacs가 시스템 시작 또는 로그인 시간에 데몬을 시작하고 출력이 기록되거나 버리게 됨
Trey

1
@Trey : 오류 신호는 기능 이 아닌 기능 (또는 아직 낮음) desktop에 있어야 y-or-n-p합니다. 시작 중에 발생한 오류 표시를 지연시키는 메커니즘이 있으므로 첫 번째 emacsclient가 데몬에 연결될 때이를 표시하는 데 사용할 수 있습니다.
Stefan

그럼에도 불구하고, 대부분의 사용자는 잘 사용하지 않습니다 . 경고가 생성 될 때 활성 프레임이 존재하는 경우 ( 이 경우에는 프레임이 존재하지 않고) *Messages*사용 *Warnings*하지 않는 시스템은 버퍼에 대한 창을 팝업 합니다. 경고 문제 이후 첫 번째 emacsclient가 표시 될 때까지 팝업을 연기하기가 쉽지 않습니다. 그렇게 할 수 있다면, 사전 클라이언트 경고를 제안하는 것이 매우 이상적입니다. (나는 시작에 사용자 빗질 의심 !)yes-or-no-p*Messages*
Trey
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.