Chế độ Daemon: Trì hoãn lời nhắc tương tác khi khởi động?


16

(Lưu ý rằng, tiêu đề ngược lại, câu hỏi này không giống như Làm thế nào để bắt đầu trong chế độ trình nền và loại bỏ các hộp thoại tương tác ? , Vì câu hỏi đó đã được "trả lời" bởi người gửi loại bỏ những gì gây ra một dấu nhắc cụ thể xuất hiện.)

Tôi muốn biết liệu có một cách chung nào để không emacs --daemonbị treo mãi mãi khi chờ câu trả lời cho lời nhắc được hiển thị trong xe buýt nhỏ chưa tồn tại.

Không thể kết nối với một emacsclient để trả lời các lời nhắc này, bởi vì máy chủ không khởi động cho đến khi Emacs kết thúc chuỗi khởi động. (Điều này có nghĩa là, nếu bạn đã đặt ALTERNATE_EDITOR thành chuỗi trống, điều này làm cho emacsclientmáy chủ không thể tìm thấy máy chủ bắt đầu một trình nền mới, bạn có thể kết thúc với nhiều trình nền Emacs bị kẹt và chờ đợi.) Tôi phải killall emacskhắc phục sự cố trước khi tiếp tục.

Tôi có thể chơi whack-a-mol với mỗi thứ gây ra một dấu nhắc khi khởi động khi tôi xác định nó (bằng cách khởi động Emacs ở chế độ không phải daemon và xem những gì nó yêu cầu), nhưng đó không phải là giải pháp vì nó không thể dừng daemon tiếp theo từ treo khi khởi động vì một lý do mới.

Để đưa ra một ví dụ: một lý do phổ biến mà nó sẽ bị treo là sau khi khởi động lại hệ thống hoặc sự cố Emacs, khi Emacs sau khởi động lại đầu tiên muốn biết liệu có ổn không khi đánh cắp các lockfiles từ Emacs không còn tồn tại. Tôi có thể khắc phục điều đó bằng cách tạo lời khuyên để khiến lời nhắc đó luôn trả lời "có" mà không cần tương tác. Nhưng sau đó, một trong những tệp được mở ở phiên lưu trước đó là tệp TRAMP yêu cầu mật khẩu sudo hoặc SSH, do đó, trình nền bị kẹt chờ trong dấu nhắc mật khẩu. Vì vậy, tôi khắc phục điều đó bằng cách chỉnh sửa thủ công tệp phiên (có vihoặc emacs -q!) Để xóa các tệp vi phạm, nhưng điều đó không ngăn nó xảy ra vào lần tới.

Vì vậy, tôi có thể dừng tải phiên của mình một cách tự động khi khởi động và thay đổi nó thành lệnh tôi phải thực hiện thủ công từ emacsclient đầu tiên của mình. Nhưng nếu nó không tải phiên của tôi dưới nền để nó sẵn sàng vào lúc tôi sẵn sàng sử dụng nó, toàn bộ mục đích của daemon sẽ bị mất!

Vì vậy, những gì tôi muốn là:

  • (Tốt nhất) Một số cách để trì hoãn nhắc nhở xe buýt nhỏ cho đến khi tôi mở một emacsclient, trong khi vẫn hoàn thành phần còn lại của việc khởi tạo.
  • (OK) Một số cách để thực hiện tất cả các lời nhắc của xe buýt nhỏ mà tôi đã không khuyên khác nếu như được mô tả ở trên chỉ cần quay lại notrừ khi một emacsclient đang chạy. Tôi có thể sống với bộ đệm TRAMP của mình bị lỗi miễn là nó hoạt động được.

Có cách nào để đạt được một trong những mục tiêu này không?


Có cách nào để tái tạo các loại vấn đề này theo chương trình để cộng đồng có thể khắc phục sự cố không?
Melioratus

1
Chà, như tôi đã viết ở dòng đầu tiên, khá dễ dàng để sửa một ví dụ đã cho ... "Bác sĩ, thật đau khi tôi làm điều này ..." "Vậy thì đừng làm thế." Vấn đề là trường hợp chung. Nhưng một cách đơn giản để tạo ra sự cố là khởi động khôi phục máy tính để bàn (read-desktop), sau đó, trước khi chạy emacs --daemon, hãy tạo một tệp khóa không có thật bằng cách đặt một số nguyên vào .emacs.desktop.lock ( không may đặt tệp đó vào đâu, tùy thuộc vào cấu hình của bạn , nhưng có thể là homedir của bạn hoặc ~ / .emacs.d / .
Trey

1
Đây là một trường hợp thường được đề cập ở đây, ví dụ: emacs.stackexchange.com/questions/8147/ và hoặc emacs.stackexchange.com/questions/31621/ trộm có thể cung cấp ngữ cảnh.
Trey

Lỗi này có vẻ liên quan: Lỗi # 13697 - Một cách để biết liệu Emacs có thể tương tác với người dùng hay không , nhưng theo tôi biết thì không có ai làm việc với nó.
npostavs

@npostavs Cảm ơn vì liên kết tôi đã chú thích lỗi, mặc dù nó đã bắt đầu sai mà tôi đã nhận xét ở đây (kể từ khi xóa) trước khi tôi phát hiện ra!
Trey

Câu trả lời:


2

Thảo luận của chúng tôi đã xóa rằng bạn không có bất kỳ máy chủ X nào chạy điều này làm cho giải pháp đầu tiên của tôi trở nên vô dụng đối với bạn.

Sau đây tôi trình bày một giải pháp thứ hai hoạt động với các khung thiết bị đầu cuối văn bản.

Khi khởi tạo của bạn yêu cầu người dùng nhập thông qua một chức năng được khuyên dùng với avoid-initial-terminalEmacs sẽ đợi cho đến khi bạn mở khung thiết bị đầu cuối văn bản. Lời nhắc xuất hiện trong bộ thu nhỏ của khung đó và bạn có thể đưa ra phản hồi tương tác của mình.

Thông tin liên quan đến mã được đưa ra dưới dạng nhận xét trong mã. Có TODOcác điểm đánh dấu với các mô tả cho bạn biết nơi để chèn cấu hình của riêng bạn. Hiện tại có các hình thức kiểm tra trong đó xác nhận mã.

;; 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")

Kiểm tra: Emacs-phiên bản: 26.1

1) Chạy emacs --daemontrên bàn điều khiển.

2) Chạy emacsclient --ttytrên bàn điều khiển khác. Bạn được yêu cầu có mật khẩu và chuỗi. Sau đó, bạn cũng được yêu cầu trả lời truy vấn y-hoặc-np.


3

Không chính xác những gì bạn đang yêu cầu nhưng có thể là một giải pháp cho vấn đề ban đầu của bạn:

Tôi muốn biết liệu có cách nào chung để giữ emacs --daemon không bị treo mãi không chờ câu trả lời cho lời nhắc được hiển thị trong xe buýt nhỏ chưa tồn tại.

Nếu daemon cung cấp cho bạn một khung đồ họa để trả lời các câu hỏi phát sinh trong giai đoạn khởi động của nó, bạn không bị kẹt nữa.

Mã dưới đây xác định một lời khuyên chung my-with-initial-framemở ra một khung trên màn hình có sẵn đầu tiên (ví dụ :0.0:).

Lời khuyên đó có thể được thêm dễ dàng vào các lệnh truy vấn như y-or-n-phoặc read-passwd, như được trình bày dưới đây.

Chỉ cần mở một khung cho bạn một khả năng khá thô để trả lời các truy vấn trên giao diện người dùng. Người ta cũng có thể sử dụng một hộp thoại cho y-or-n-pnhưng điều đó sẽ yêu cầu các giải pháp đặc biệt cho các lệnh truy vấn cụ thể. Tôi muốn tránh điều đó.

Nếu bạn thử mã đó trong tệp init của bạn, hãy chắc chắn rằng đó là điều đầu tiên ở đó.

(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))

Kiểm tra:

Giả định:

Có một xserver đang chạy mà các chương trình có thể kết nối thông qua DISPLAYbiến môi trường.

Đầu vào tại xterm:

emacs --daemon

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

Ở đó mở một khung với y-or-n-pdấu nhắc truy vấn A (y or n). Trả lời truy vấn đó và thử lại:

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

Truy vấn mới với dấu nhắc B (y or n)trong cùng một khung. Đóng khung đó, ví dụ, với C-x 5 0và thử lại:

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

Một khung mới mở ra với dấu nhắc truy vấn C (y or n).

Các công việc tương tự cho đầu vào mật khẩu.


@Trey Tôi có một số vấn đề với mã của tôi (thực sự là với thử nghiệm). Khởi động máy chủ x không hoạt động lần đầu tiên. Tôi đã không nhận thấy ban đầu vì tôi đã không khởi động lại daemon. Tôi đã sửa nó ngay bây giờ. Vui lòng kiểm tra lại. Cảm ơn.
Tobias

Linux ảo của tôi không có thiết bị đầu cuối đồ họa đi kèm, vì vậy tôi không thể chạy xterm. Ngoài ra, tôi không nghĩ giải pháp này có thể hiệu quả với những người làm giáo dục nếu bạn có trình nền được thiết lập để chạy khi khởi động, nó sẽ cố mở một khung ở phía trên màn hình đăng nhập, không được phép, vì vậy nó tai nạn
Trey

Tobias, xin lỗi nếu tiếng brusque ở trên nghe tôi đã trả lời trên điện thoại của tôi và có thể đã tự cắt ngắn, vì vậy hãy để tôi thử giải thích: lợi thế duy nhất tôi có thể thấy về những gì bạn mô tả khi không sử dụng daemon và chạy server-startkhi kết thúc khởi động thay vào đó, nếu bạn có một khởi động sạch, bạn sẽ không phải chờ đợi. Nhưng ... bạn sẽ phải chờ, vì trừ khi tôi hiểu nhầm, bạn không thể đặt nhiệm vụ khởi động trình nền Emacs vào tập lệnh đăng nhập hệ thống của bạn vì GUI sẽ không khả dụng. (Và trong trường hợp như của tôi, nó cũng sẽ không bao giờ muộn hơn.)
Trey

@Trey Bạn có thể tham gia trò chuyện không?
Tobias

1

Tôi nghĩ nói chung việc trì hoãn các lời nhắc sẽ khó khăn, nhưng việc thay đổi Emacs khá dễ dàng để các lời nhắc đó ngay lập tức báo hiệu lỗi.

Không chỉ vậy, nhưng nếu bạn không thể trả lời những lời nhắc đó mà không có nhiều môn thể dục dụng cụ, tôi nghĩ rằng nó đủ điều kiện là một lỗi, vì vậy tôi khuyên bạn nên gửi báo cáo lỗi cho điều đó.


Tôi nghĩ rằng tôi cần một chút chi tiết. Hãy xem xét khóa tập tin lưu trên máy tính để bàn mà tôi đề cập trong phần bình luận cho tiền thưởng ở trên. Làm thế nào một người có thể đi về việc thay đổi Warning: desktop file appears to be in use by PID xxx. Using it may cause conflicts. Use it anyway? (y or n)lời nhắc thành một lỗi, mà không đề cập cụ thể đến "máy tính để bàn" theo một cách nào đó (bởi vì theo cách đó, là không chung chung, nằm ở một nốt ruồi)?
Trey

Stefan, cũng có một vấn đề không làm phiền tôi vì tôi không chạy trình nền Emacs theo cách này, nhưng để đưa ra một câu trả lời chung hữu ích có thể cần giải quyết: lỗi nghiêm trọng sẽ khiến Emacs khởi động thông qua systemd hoặc các cơ quan giám sát khác để khởi động lại trong một vòng lặp. Nhưng bỏ qua lỗi và chỉ đăng nhập vào *Messages*có lẽ là không đủ đối với khách hàng đầu tiên kết nối rằng một cái gì đó có thể bị sai lệch nghiêm trọng và cần được chú ý ngay lập tức trước khi người dùng thử bất kỳ hoạt động trạng thái nào.
Trey

(Để làm rõ cho những người không sử dụng trình nền daemon nếu bạn khởi động thủ công, thông qua emacs --daemonhoặc bằng cách bắt đầu emacsclientvới ALTERNATE_EDITORbiến môi trường được đặt thành chuỗi trống, bạn sẽ thấy đầu ra thường được *Messages*lặp lại trong thiết bị đầu cuối cho đến khi trình nền hoàn thành việc khởi tạo và Emacs đã sẵn sàng. Nhưng nhiều Emacs đã khởi động trình nền khi khởi động hệ thống hoặc thời gian đăng nhập, và đầu ra được ghi hoặc vứt đi.
Trey

1
@Trey: báo hiệu lỗi không nên có desktopnhưng trong y-or-n-pchức năng (hoặc thấp hơn). Chúng tôi có một số cơ chế để trì hoãn hiển thị các lỗi đã xảy ra trong quá trình khởi động, vì vậy chúng tôi có thể sử dụng điều đó để hiển thị chúng khi emacsclient đầu tiên kết nối với daemon.
Stefan

Tuy nhiên, trong cả hai trường hợp, hầu hết người dùng không sử dụng liên tục *Messages*trong khi *Warnings*hệ thống ít sử dụng sẽ bật cửa sổ vào bộ đệm nếu khung hoạt động tồn tại khi cảnh báo được tạo, trong trường hợp này, không có khung nào tồn tại và nó không tồn tại Có vẻ như dễ dàng trì hoãn cửa sổ bật lên cho đến khi người đầu tiên tiếp theo sau sự cố cảnh báo. Nếu điều đó có thể được thực hiện, đề nghị của bạn về việc đưa ra một yes-or-no-pcảnh báo trước khách hàng thay vào đó sẽ khá lý tưởng. (Tôi nghi ngờ người dùng kết hợp *Messages*khi khởi động!)
Trey
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.