From 61695d9671368cf216587a28ee2ea9d90ccf4b1a Mon Sep 17 00:00:00 2001 From: Akib Azmain Turja Date: Thu, 15 Dec 2022 20:18:04 +0600 Subject: [PATCH] Decrease regexp usage while parsing output * eat.el (eat--t-handle-output): Don't use regular expressions while parsing plain text and CSI sequences. Remove useless code from VT300-specific charset set sequence parser. --- eat.el | 379 +++++++++++++++++++++++++++++++-------------------------- 1 file changed, 207 insertions(+), 172 deletions(-) diff --git a/eat.el b/eat.el index dbeb80f..996e966 100644 --- a/eat.el +++ b/eat.el @@ -2609,27 +2609,20 @@ DATA is the selection data encoded in base64." (defun eat--t-handle-output (output) "Parse and evaluate OUTPUT." (let ((index 0)) - (while (< index (length output)) + (while (/= index (length output)) (pcase-exhaustive (eat--t-term-parser-state eat--t-term) ('nil - ;; Regular expression to find the end of plain text. - (let ((match (string-match - (1value (rx (or ?\0 ?\a ?\b ?\t ?\n ?\v - ?\f ?\r ?\C-n ?\C-o ?\e - #x7f))) - output index))) - (if (not match) - ;; The regex didn't match, so everything left to handle - ;; is just plain text. - (progn - (eat--t-write output index) - (setq index (length output))) - (when (/= match index) - ;; The regex matched, and the position is after the - ;; current position. Process the plain text between - ;; them and advance to the control sequence. - (eat--t-write output index match) - (setq index match)) + (let ((ins-beg index)) + (while (and (/= index (length output)) + (not (memq (aref output index) + '( ?\0 ?\a ?\b ?\t ?\n ?\v ?\f ?\r + ;; TODO: Why #x7f? + ?\C-n ?\C-o ?\e #x7f)))) + (cl-incf index)) + (when (/= ins-beg index) + ;; Insert. + (eat--t-write output ins-beg index)) + (when (/= index (length output)) ;; Dispatch control sequence. (cl-incf index) (pcase-exhaustive (aref output (1- index)) @@ -2719,7 +2712,7 @@ DATA is the selection data encoded in base64." ;; ESC [, or CSI. (?\[ (1value (setf (eat--t-term-parser-state eat--t-term) - '(read-csi "")))) + '(read-csi-format)))) ;; ESC ], or OSC. (?\] (1value (setf (eat--t-term-parser-state eat--t-term) @@ -2741,151 +2734,196 @@ DATA is the selection data encoded in base64." ;; ESC o. (?o (eat--t-change-charset 'g3))))) - (`(read-csi ,buf) - (let ((match (string-match (rx (any (#x40 . #x7e))) - output index))) - (if (not match) - (progn - (setf (eat--t-term-parser-state eat--t-term) - `(read-csi ,(concat buf (substring output - index)))) - (setq index (length output))) - (setf (eat--t-term-parser-state eat--t-term) nil) - (pcase - (let ((str (concat buf (substring output index - match))) - (format nil) - (intermediate-bytes "")) - (save-match-data - (when (string-match - (rx (zero-or-more (any (?\s . ?/))) - string-end) - str) - (setq str (substring - str 0 (match-beginning 0)) - intermediate-bytes - (match-string 0 str)))) - (when (and (not (string-empty-p str)) - (= (aref str 0) ??)) - (setq format ?? str (substring str 1))) - (when (and (not (string-empty-p str)) - (= (aref str 0) ?>)) - (setq format ?> str (substring str 1))) - (when (and (not (string-empty-p str)) - (= (aref str 0) ?=)) - (setq format ?= str (substring str 1))) - (setq index (match-end 0)) - (list - (concat intermediate-bytes - (match-string 0 output)) - format - (cond - ((string-empty-p str) '((nil))) - ((<= #x30 (aref str 0) #x3b) - (mapcar (lambda (p) - (mapcar (lambda (s) - (unless (string-empty-p s) - (string-to-number s))) - (split-string p ":"))) - (split-string str ";"))) - (t str)))) - ;; CSI @. - (`("@" nil ,(and (pred listp) params)) - (eat--t-insert-char (caar params))) - ;; CSI A. - ;; CSI k. - (`(,(or "A" "k") nil ,(and (pred listp) params)) - (eat--t-cur-up (caar params))) - ;; CSI B. - ;; CSI e. - (`(,(or "B" "e") nil ,(and (pred listp) params)) - (eat--t-cur-down (caar params))) - ;; CSI C. - ;; CSI a. - (`(,(or "C" "a") nil ,(and (pred listp) params)) - (eat--t-cur-right (caar params))) - ;; CSI D. - ;; CSI j. - (`(,(or "D" "j") nil ,(and (pred listp) params)) - (eat--t-cur-left (caar params))) - ;; CSI E. - (`("E" nil ,(and (pred listp) params)) - (eat--t-beg-of-prev-line (caar params))) - ;; CSI F. - (`("F" nil ,(and (pred listp) params)) - (eat--t-beg-of-next-line (caar params))) - ;; CSI G. - ;; CSI `. - (`(,(or "G" "`") nil ,(and (pred listp) params)) - (eat--t-cur-horizontal-abs (caar params))) - ;; CSI ; H - ;; CSI ; f - (`(,(or "H" "f") nil ,(and (pred listp) params)) - (eat--t-goto (caar params) (caadr params))) - ;; CSI I. - (`("I" nil ,(and (pred listp) params)) - (eat--t-horizontal-tab (caar params))) - ;; CSI J. - (`("J" nil ,(and (pred listp) params)) - (eat--t-erase-in-disp (caar params))) - ;; CSI K. - (`("K" nil ,(and (pred listp) params)) - (eat--t-erase-in-line (caar params))) - ;; CSI L. - (`("L" nil ,(and (pred listp) params)) - (eat--t-insert-line (caar params))) - ;; CSI M. - (`("M" nil ,(and (pred listp) params)) - (eat--t-delete-line (caar params))) - ;; CSI P. - (`("P" nil ,(and (pred listp) params)) - (eat--t-delete-char (caar params))) - ;; CSI S. - (`("S" nil ,(and (pred listp) params)) - (eat--t-scroll-up (caar params))) - ;; CSI T. - (`("T" nil ,(and (pred listp) params)) - (eat--t-scroll-down (caar params))) - ;; CSI X. - (`("X" nil ,(and (pred listp) params)) - (eat--t-erase-char (caar params))) - ;; CSI Z. - (`("Z" nil ,(and (pred listp) params)) - (eat--t-horizontal-backtab (caar params))) - ;; CSI b. - (`("b" nil ,(and (pred listp) params)) - (eat--t-repeat-last-char (caar params))) - ;; CSI c. - ;; CSI > c. - (`("c" ,format ,(and (pred listp) params)) - (eat--t-send-device-attrs params format)) - ;; CSI d. - (`("d" nil ,(and (pred listp) params)) - (eat--t-cur-vertical-abs (caar params))) - ;; CSI ... h. - ;; CSI ? ... h. - (`("h" ,format ,(and (pred listp) params)) - (eat--t-set-modes params format)) - ;; CSI ... l. - ;; CSI ? ... l. - (`("l" ,format ,(and (pred listp) params)) - (eat--t-reset-modes params format)) - ;; CSI ... m. - (`("m" nil ,(and (pred listp) params)) - (eat--t-set-sgr-params params)) - ;; CSI 6 n. - ('("n" nil ((6))) - (eat--t-device-status-report)) - ;; CSI ; r. - (`("r" nil ,(and (pred listp) params)) - (eat--t-change-scroll-region (caar params) - (caadr params))) - ;; CSI s. - (`("s" nil nil) - (eat--t-save-cur)) - ;; CSI u. - (`("u" nil nil) - (eat--t-restore-cur)))))) + ('(read-csi-format) + (let ((format nil)) + (pcase (aref output index) + (?? + (setq format ??) + (cl-incf index)) + (?> + (setq format ?>) + (cl-incf index)) + (?= + (setq format ?=) + (cl-incf index))) + (setf (eat--t-term-parser-state eat--t-term) + `(read-csi-params ,format ,(list (list nil)))))) + (`(read-csi-params ,format ,params) + ;; Interpretion of the parameter depends on `format' and + ;; other things (including things we haven't got yet) + ;; according to the standard. We don't recognize any other + ;; format of parameters, so we can skip any checks. + (let ((loop t)) + (while loop + (cond + ((= index (length output)) + ;; Output exhausted. We need to wait for more. + (setf (eat--t-term-parser-state eat--t-term) + `(read-csi-params ,format ,params)) + (setq loop nil)) + ((not (<= ?0 (aref output index) ?\;)) + ;; End of parameters. + ;; NOTE: All parameter and their parts are in reverse + ;; order! + (setf (eat--t-term-parser-state eat--t-term) + `(read-csi-function ,format ,params nil)) + (setq loop nil)) + (t + (cond + ((= (aref output index) ?:) + ;; New parameter substring. + (push nil (car params))) + ((= (aref output index) ?\;) + ;; New parameter. + (push (list nil) params)) + (t ; (<= ?0 (aref output index) ?9) + ;; Number, save it. + (setf (caar params) + (+ (* (or (caar params) 0) 10) + (- (aref output index) #x30))))) + (cl-incf index)))))) + (`(read-csi-function ,format ,params ,function) + (let ((loop t)) + (while loop + (cond + ((= index (length output)) + (setf (eat--t-term-parser-state eat--t-term) + `(read-csi-function ,format ,params ,function)) + (setq loop nil))) + (push (aref output index) function) + (cl-incf index) + (when (<= ?@ (car function) ?~) + ;; Now we have enough information to execute it! + (setq loop nil) + (setf (eat--t-term-parser-state eat--t-term) nil) + ;; NOTE: `function' and `params' are in reverse order! + (pcase (list function format params) + ;; CSI @. + (`((?@) nil ((,n))) + (eat--t-insert-char n)) + ;; CSI A. + ;; CSI k. + (`((,(or ?A ?k)) nil ((,n))) + (eat--t-cur-up n)) + ;; CSI B. + ;; CSI e. + (`((,(or ?B ?e)) nil ((,n))) + (eat--t-cur-down n)) + ;; CSI C. + ;; CSI a. + (`((,(or ?C ?a)) nil ((,n))) + (eat--t-cur-right n)) + ;; CSI D. + ;; CSI j. + (`((,(or ?D ?j)) nil ((,n))) + (eat--t-cur-left n)) + ;; CSI E. + (`((?E) nil ((,n))) + (eat--t-beg-of-prev-line n)) + ;; CSI F. + (`((?F) nil ((,n))) + (eat--t-beg-of-next-line n)) + ;; CSI G. + ;; CSI `. + (`((,(or ?G ?`)) nil ((,n))) + (eat--t-cur-horizontal-abs n)) + ;; CSI ; H + ;; CSI ; f + (`((,(or ?H ?f)) nil ,(and (pred listp) params)) + (eat--t-goto (caadr params) (caar params))) + ;; CSI I. + (`((?I) nil ((,n))) + (eat--t-horizontal-tab n)) + ;; CSI J. + (`((?J) nil ((,n))) + (eat--t-erase-in-disp n)) + ;; CSI K. + (`((?K) nil ((,n))) + (eat--t-erase-in-line n)) + ;; CSI L. + (`((?L) nil ((,n))) + (eat--t-insert-line n)) + ;; CSI M. + (`((?M) nil ((,n))) + (eat--t-delete-line n)) + ;; CSI P. + (`((?P) nil ((,n))) + (eat--t-delete-char n)) + ;; CSI S. + (`((?S) nil ((,n))) + (eat--t-scroll-up n)) + ;; CSI T. + (`((?T) nil ((,n))) + (eat--t-scroll-down n)) + ;; CSI X. + (`((?X) nil ((,n))) + (eat--t-erase-char n)) + ;; CSI Z. + (`((?Z) nil ((,n))) + (eat--t-horizontal-backtab n)) + ;; CSI b. + (`((?b) nil ((,n))) + (eat--t-repeat-last-char n)) + ;; CSI c. + ;; CSI > c. + (`((?c) ,format ,(and (pred listp) params)) + ;; Reverse `params' to get it into the correct + ;; order. + (setq params (nreverse params)) + (let ((p params)) + (while p + (setf (car p) (nreverse (car p))) + (setq p (cdr p)))) + ;; TODO: This function kinda a HACK. + (eat--t-send-device-attrs params format)) + ;; CSI d. + (`((?d) nil ((,n))) + (eat--t-cur-vertical-abs n)) + ;; CSI ... h. + ;; CSI ? ... h. + (`((?h) ,format ,(and (pred listp) params)) + ;; Reverse `params' to get it into the correct + ;; order. + (setq params (nreverse params)) + (let ((p params)) + (while p + (setf (car p) (nreverse (car p))) + (setq p (cdr p)))) + (eat--t-set-modes params format)) + ;; CSI ... l. + ;; CSI ? ... l. + (`((?l) ,format ,(and (pred listp) params)) + ;; Reverse `params' to get it into the correct + ;; order. + (setq params (nreverse params)) + (let ((p params)) + (while p + (setf (car p) (nreverse (car p))) + (setq p (cdr p)))) + (eat--t-reset-modes params format)) + ;; CSI ... m. + (`((?m) nil ,(and (pred listp) params)) + ;; Reverse `params' to get it into the correct + ;; order. + (setq params (nreverse params)) + (let ((p params)) + (while p + (setf (car p) (nreverse (car p))) + (setq p (cdr p)))) + (eat--t-set-sgr-params params)) + ;; CSI 6 n. + ('((?n) nil ((6))) + (eat--t-device-status-report)) + ;; CSI ; r. + (`((?r) nil ,(and (pred listp) params)) + (eat--t-change-scroll-region (caadr params) + (caar params))) + ;; CSI s. + (`((?s) nil nil) + (eat--t-save-cur)) + ;; CSI u. + (`((?u) nil nil) + (eat--t-restore-cur))))))) (`(,(and (or 'read-dcs 'read-sos 'read-osc 'read-pm 'read-apc) state) ,buf) @@ -3023,13 +3061,10 @@ DATA is the selection data encoded in base64." ;; ESC + B. ("B" 'us-ascii))))))) (`(read-charset-vt300 ,_slot) - (let ((_charset (aref output index))) - (cl-incf index) - (setf (eat--t-term-parser-state eat--t-term) nil) - (pcase charset - ;; TODO: Currently ignored. It is here just to recognize - ;; the control sequence. - ))))))) + (cl-incf index) + (setf (eat--t-term-parser-state eat--t-term) nil) + ;; Nothing. This is here to just recognize the sequence. + ))))) (defun eat--t-resize (width height) "Resize terminal to WIDTH x HEIGHT."