Как написать достойный фильтр процесса? - PullRequest
3 голосов
/ 19 мая 2010

Я создаю программу, которая взаимодействует с Emacs, и одной из проблем, с которыми я сталкиваюсь, является написание функции фильтра процессов Emacs. Его входная строка представляет собой серию s-выражений для оценки. Вот образец:

(gimme-append-to-buffer "25 - William Christie dir, Les Arts Florissants - Scene 2. Prelude - Les Arts Florissants\n")
(gimme-append-to-buffer "26 - William Christie dir, Les Arts Florissants - Cybele: 'Je Veux Joindre' - Les Arts Florissants\n")
(gimme-append-to-buffer "27 - William Christie dir, Les Arts Florissants - Scene 3. Cybele: 'Tu T'Etonnes, Melisse' - Les Arts Florissants\n")
(gimme-append-to-buffer "28 - William Christie dir, Les Arts Florissants - Cybele: 'Que Les Plus Doux Zephyrs'. Scene 4. - Les Arts Florissants\n")
(gimme-append-to-buffer "29 - William Christie dir, Les Arts Florissants - Entree Des Nations - Les Arts Florissants\n")
(gimme-append-to-buffer "30 - William Christie dir, Les Arts Florissants - Entree Des Zephyrs - Les Arts Florissants\n")
(gimme-append-to-buffer "31 - William Christie dir, Les Arts Florissants - Choeur Des Nations' 'Que Devant Vous' - Les Arts Florissants\n")
(gimme-append-to-buffer "32 - William Christie dir, Les Arts Florissants - Atys: 'Indigne Que Je Suis' - Les Arts Florissants\n")
(gimme-append-to-buffer "33 - William Christie dir, Les Arts Florissants - Reprise Du Choeur Des Nations : 'Que Devant Nous' - Les Arts Florissants\n")
(gimme-append-to-buffer "34 - William Christie dir, Les Arts Flor*emphasized text*issants - Reprise De L'Air Des Zephyrs - Les Arts Florissants\n")

Первая проблема, с которой я столкнулся, заключается в том, что строка, так или иначе, формируется не полностью, когда функция вызывается так, поэтому написание чего-то вроде (mapcar 'eval (format "(%s)" input-string)) не будет работать.

Для решения этой первой проблемы я использовал цикл. Полная функция, которую я написал:

 (defun eval-all-sexps (s)
   (loop for x = (ignore-errors (read-from-string s))
          then (ignore-errors (read-from-string (substring s position)))
          while x
          summing (or (cdr x) 0) into position
          doing (eval (car x))))

Теперь вторая проблема, которая обнаружилась, состоит в том, что функция вызывается дважды с несколько большим вводом, сначала с допустимым, но частичным содержимым, затем с тем, что похоже на фрагменты оставшихся данных.

Чтобы решить эту проблему, я рассматриваю возможность использования нежелательной переменной для удержания того, что осталось от цикла, и последующего объединения ее с входом следующего вызова, но мне было интересно, есть ли у вас, ребята, какие-либо другие предложения о том, справиться с такой проблемой более изящно.

Спасибо!

Ответы [ 2 ]

3 голосов
/ 19 мая 2010

Это то, что я делаю в режиме оболочки, который я использую.
Я ищу специальную строку конца записи в выводе процесса, чтобы знать, когда вывод завершен. До тех пор я конкатить куски.

(defun my-shell-exec-filter (process result)
  (let ((end-of-result (string-match my-shell-end-of-record-string result)))
    (if (and end-of-result
             (numberp end-of-result)
             (> end-of-result 0))
        (setq my-shell-reply 
              (concat my-shell-reply
                      (substring (substring result 0 end-of-result) 0 -1)))

      (progn
        (setq my-shell-reply (concat my-shell-reply result))
        (accept-process-output process my-shell-exec-timeout 5)))))

Это не совсем правильно, потому что строка конца записи может быть разделена на несколько вызовов этого фильтра fn. Таким образом, чтобы быть правильным, он должен сначала согласиться, а затем проверить на совпадение. Но в любом случае вы поняли идею.

Также он повторяется, и из-за этого для очень очень длинного ввода может возникнуть исключение переполнения стека. Так что это определенно не так чисто, как хотелось бы.

Дело начинается с

      (setq my-shell-reply nil) 
      (set-process-filter proc my-shell-exec-filter)
      (process-send-string proc "whatever...") 
      (if (not (accept-process-output proc my-shell-exec-timeout 100))
          (error "unexpected response."))

      ;; examine my-shell-reply here ... 
2 голосов
/ 31 мая 2010

Мое окончательное решение было:

(defun eval-all-sexps (s)
  (let ((s (concat gimme-filter-remainder s)))
    (setq gimme-filter-remainder
          (loop for x = (ignore-errors (read-from-string s))
                then (ignore-errors (read-from-string (substring s position)))
                while x
                summing (or (cdr x) 0) into position
                doing (eval (car x))
                finally (return (substring s position))))))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...