Режим демона: відкласти інтерактивні підказки при запуску?


16

(Зауважте, що, наголошуючи на протилежне, це питання не те саме, як запуститись у демон-режимі та придушити інтерактивні діалоги? Оскільки на це питання "відповів" подавець, усуваючи те, що спричиняло появу певного запиту.)

Мені хотілося б знати, чи існує загальний спосіб утриматися emacs --daemonвід вивішування вічно, чекаючи відповіді на підказку, відображену в мінібуфері, який ще не існує.

Підключитися до emacsclient не можна, щоб відповісти на ці підказки, оскільки сервер не запускається, поки Emacs не завершить послідовність запуску. (Це означає, що якщо у вас ALTERNATE_EDITOR встановлено в порожній рядок, завдяки чому emacsclientсервер не може знайти запуск нового демона, ви можете закінчити з декількома демонами Emacs, усі застрягли і чекаючи.) Я повинен killall emacsвирішити проблему перш ніж продовжувати.

Я можу грати з бездротовою моллю з кожною річчю, викликаючи підказку при запуску, коли я її ідентифікую (запускаючи Emacs в недемоновому режимі і бачачи, що він просить), але це не рішення, оскільки він не може зупинити наступний демон від зависання при запуску з нової причини.

Для прикладу: поширена причина, яку вона зависла, - це після перезавантаження системи або аварії Emacs, коли перший Emacs після перезавантаження хотів дізнатися, чи добре вкрасти замкові файли у неіснуючих Emacs. Я міг би це виправити, створюючи поради, щоб цей підказник завжди відповідав "так" без взаємодії. Але потім, один з файлів, який був відкритий на попередньому сеансі збереження, - це файл TRAMP, який вимагає sudo або SSH-пароля, тому демон демонстровно затримався в очікуванні на запит пароля. Тож я це виправляю, вручну редагуючи сесійний файл (з viабо emacs -q!), Щоб видалити файли, які порушують правопорушення, але це не перешкоджає наступному разу.

Отже, я можу припинити завантаження сеансу автоматично під час запуску і змінити його на команду, яку я повинен виконувати вручну з першого мого emacsclient. Але якщо він не завантажує сеанс у фоновому режимі, щоб він був готовий до моменту, коли я готовий його використовувати, вся мета демона втрачається!

Отже, що мені хотілося б:

  • (Найкраще) Якимось способом відкласти підказки minibuffer, поки я не відкрию emacsclient, доки не завершую решту ініціалізації.
  • (ОК) Якимось способом зробити всі підказки мінібуфера, які я вже не радив, інакше як описано вище, просто повертайтеся, noякщо не працює emacsclient. Я можу жити, коли мої буфери TRAMP помиляються до тих пір, поки це в основному працює.

Чи є спосіб досягти будь-якої з цих цілей?


Чи є спосіб відтворити подібні проблеми програмно, щоб громада могла усунути неполадки?
Меліорат

1
Ну, як я писав у першому рядку, виправити даний приклад досить просто ... "Докторе, боляче, коли я це роблю ..." "Тоді не робіть цього". Питання - загальна справа. Але простий спосіб створити проблему - це відновити робочий стіл запуску через те (read-desktop), перш ніж запустити emacs --daemon, створити фіктивний файл блокування, помістивши ціле число в .emacs.desktop.lock (куди помістити цей файл, на жаль, залежить від вашої конфігурації , але, ймовірно, або ваш homedir, або ~ / .emacs.d / .
Трей

1
Це часто згадуваний випадок, наприклад: emacs.stackexchange.com/questions/8147/… або emacs.stackexchange.com/questions/31621/… може дати контекст.
Трей

Ця помилка здається пов'язаною: Помилка № 13697 - спосіб сказати, чи може Emacs взаємодіяти з користувачем , але ніхто не працював над цим, наскільки я знаю.
npostavs

@npostavs Дякую за посилання - я помітив помилку, хоча це було помилковим початком, що я коментував тут (з моменту видалення), перш ніж я зрозумів це!
Трей

Відповіді:


2

Під час нашої дискусії з'ясувалося, що у вас немає жодного X-сервера, який працює на цьому, робить моє перше рішення непотрібним для вас.

Далі я представляю друге рішення, яке працює з текстовими термінальними кадрами.

Коли ваша ініціалізація вимагає введення користувачем через один, функції, рекомендовані в avoid-initial-terminalEmacs, чекають, поки ви відкриєте текстовий термінальний кадр. Підказка відображається в мінібуфері цього кадру, і ви можете дати свою інтерактивну відповідь.

Інформація, що стосується коду, подається як коментарі до коду. Є 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")

Тест: Emacs-версія: 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))

Тест:

Припущення:

Мати запущений xserver, до якого програми можуть підключатися через DISPLAYзмінну середовища.

Вхід при 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-сервера не працював з першого разу. Я не помітив спочатку, оскільки не перезапустив демон. Я зараз це виправив. Перевірте ще раз. Спасибі.
Тобіас

У моєму віртуальному Linux не встановлений графічний термінал, тому я не можу запускатись xterm. Крім того, я не думаю, що це рішення може працювати для тих, хто це робить - якщо у вас встановлений демон для запуску при запуску, він спробує відкрити кадр вгорі екрана входу, що заборонено, так що збої.
Трей

Тобіас, вибачте, якщо вищезгадане прозвучало брусково - я відповів по телефону і, можливо, скоротив себе, тому дозвольте спробувати детальніше: єдина перевага, яку я бачу, що ви описуєте над тим, що ви не використовуєте демон і не працюєте server-startв кінці запуску. натомість, якщо у вас є чистий запуск, вам не доведеться чекати. Але ... вам доведеться почекати, тому що якщо я неправильно зрозумію, ви не можете поставити завдання запустити демон Emacs у свій скрипт для входу в систему, оскільки GUI тоді не буде доступний. (І в такому випадку, як у мене, це теж ніколи не буде.)
Трей,

@Trey Чи можете ви приєднатися до чату ?
Тобіас

1

Я думаю, що відкладати підказки в цілому буде складно, але змінити Emacs слід досить легко, щоб такі підказки негайно сигналізували про помилку.

Мало того, але якщо ви не можете відповісти на ці підказки без багато гімнастики, я думаю, що це кваліфікується як помилка, тому я рекомендую вам надіслати звіт про помилку.


Я думаю, мені потрібно трохи детальніше. Розгляньте блокування збереженого файлу на робочому столі, яке я згадую у коментарі до нагороди. Як можна було б змінити Warning: desktop file appears to be in use by PID xxx. Using it may cause conflicts. Use it anyway? (y or n)підказку на помилку, не посилаючись якимось чином на "робочий стіл" (адже такий спосіб, будучи неповноправним, брехне ")?
Трей

Стефане, також є проблема, яка мене не турбує , тому що я не запускаю демона Emacs таким чином, але для загальної корисної відповіді може знадобитися адресація: помилка фатально призведе до того, що Emacs запуститься через systemd або інших сторожових собак, щоб перезапустити в петлі. Але ігнорування помилок та просто вхід у систему *Messages*, ймовірно, недостатньо для того, щоб підключити перший клієнт, що щось може бути серйозним і потребує негайної уваги, перш ніж користувач намагатиметься здійснити будь-які оперативні дії.
Трей

(Для уточнення для тих, хто не використовує демона - якщо ви запускаєте його вручну, через emacs --daemonабо, починаючи emacsclientзі ALTERNATE_EDITORзмінної середовища, встановленої в порожній рядок, ви побачите вихід, який зазвичай *Messages*перегукується в терміналі до демона завершує ініціалізацію, і Emacs готовий. Але багато хто з Emacs запускає демон під час запуску системи або входу в систему, а вихід або записується в систему, або викидається.
Трей

1
@Trey: сигналізація помилок не повинно бути в , desktopале в y-or-n-pфункції (або знизити поки). У нас є якийсь механізм затримки відображення помилок, які сталися під час запуску, тому ми могли використовувати його для відображення їх, коли перший emacsclient підключається до демона.
Стефан

У будь-якому випадку більшість користувачів не переглядає - *Messages*і тоді, коли мало використовувана *Warnings*система вискакує вікно в буфер, якщо активний кадр існує при створенні попередження, в цьому випадку кадру немає, і він не працює Не можна легко відкласти спливаюче вікно до першого emacsclient після виходу попередження. Якщо це вдасться зробити, ваша пропозиція зробити попередження попереднього клієнта yes-or-no-pзамість цього буде цілком ідеальною. (Сумніваюсь, користувачі розчісуються *Messages*при запуску!)
Трей
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.