2010-05-19 8 views
3

Я создаю программу, которая взаимодействует с 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)))) 

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

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

Спасибо!

ответ

3

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

(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

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

(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)))))) 
Смежные вопросы