perf(org-babel): split buffer once for named-block lookups
ober
aedaa9b53b47b00f4a5f4cc91f0f8eeadbc26779
--- a/src/jerboa-emacs/org-babel.ss +++ b/src/jerboa-emacs/org-babel.ss @@ -338,60 +338,69 @@ "Resolve a :var reference. If ref-name matches a #+NAME: src block, execute it and return output. If it matches a named table, convert to list format. Otherwise return ref-name as literal." - ;; First check for a named src block - (let ((block-body (org-babel-find-named-block text ref-name))) + ;; Split the buffer once and thread the line vector through the lookups. + (let* ((lines (list->vector (string-split text #\newline))) + (block-body (org-babel-find-named-block* lines ref-name))) (if block-body ;; Found a named src block — find its language and execute - (let ((block-lang (org-babel-find-named-block-lang text ref-name))) + (let ((block-lang (org-babel-find-named-block-lang* lines ref-name))) (if block-lang (let ((result (org-babel-execute block-lang block-body (make-hash-table)))) (string-trim result)) ref-name)) ;; Check for a named table - (let ((table-data (org-babel-find-named-table text ref-name))) + (let ((table-data (org-babel-find-named-table* lines ref-name))) (if table-data table-data ref-name))))) (def (org-babel-find-named-block-lang text name) "Find the language of a named src block." - (let* ((lines (string-split text #\newline)) - (total (length lines))) + (org-babel-find-named-block-lang* + (list->vector (string-split text #\newline)) name)) + +(def (org-babel-find-named-block-lang* lines name) + "Find the language of a named src block. LINES is a vector of lines." + (let ((total (vector-length lines))) (let loop ((i 0)) (cond ((>= i total) #f) - ((let ((line (list-ref lines i))) + ((let ((line (vector-ref lines i))) (let ((m (pregexp-match "^#\\+[Nn][Aa][Mm][Ee]:\\s*(.+)" line))) (and m (string=? (string-trim (list-ref m 1)) name) (< (+ i 1) total) - (org-block-begin? (list-ref lines (+ i 1)))))) + (org-block-begin? (vector-ref lines (+ i 1)))))) ;; Found it — parse the BEGIN_SRC line for language - (let ((parsed (org-babel-parse-begin-line (list-ref lines (+ i 1))))) + (let ((parsed (org-babel-parse-begin-line (vector-ref lines (+ i 1))))) (and parsed (car parsed)))) (else (loop (+ i 1))))))) (def (org-babel-find-named-table text name) "Find a named org table and convert to a language-appropriate string. Returns comma-separated rows with pipe-separated cells, or #f." - (let* ((lines (string-split text #\newline)) - (total (length lines))) + (org-babel-find-named-table* + (list->vector (string-split text #\newline)) name)) + +(def (org-babel-find-named-table* lines name) + "Find a named org table. LINES is a vector of lines." + (let ((total (vector-length lines))) (let loop ((i 0)) (cond ((>= i total) #f) - ((let ((line (list-ref lines i))) + ((let ((line (vector-ref lines i))) (let ((m (pregexp-match "^#\\+[Nn][Aa][Mm][Ee]:\\s*(.+)" line))) (and m (string=? (string-trim (list-ref m 1)) name) (< (+ i 1) total) - (org-table-line-check? (list-ref lines (+ i 1)))))) + (org-table-line-check? (vector-ref lines (+ i 1)))))) ;; Found named table — collect rows (let table-loop ((j (+ i 1)) (rows '())) (if (or (>= j total) - (not (org-table-line-check? (list-ref lines j)))) + (not (org-table-line-check? (vector-ref lines j)))) ;; Convert to data string: list of lists (org-babel-table-to-string (reverse rows)) ;; Skip separator lines (|---|---|) - (let ((line (list-ref lines j))) + (let ((line (vector-ref lines j))) (if (pregexp-match "^\\s*\\|[-+]+\\|" line) (table-loop (+ j 1) rows) (table-loop (+ j 1) (cons (org-babel-parse-table-row line) rows))))))) @@ -590,24 +599,28 @@ (def (org-babel-find-named-block text name) "Find a named src block in text and return its body." - (let* ((lines (string-split text #\newline)) - (total (length lines))) + (org-babel-find-named-block* + (list->vector (string-split text #\newline)) name)) + +(def (org-babel-find-named-block* lines name) + "Find a named src block in LINES (a vector) and return its body." + (let ((total (vector-length lines))) (let loop ((i 0)) (cond ((>= i total) #f) - ((let ((line (list-ref lines i))) + ((let ((line (vector-ref lines i))) (let ((m (pregexp-match "^#\\+[Nn][Aa][Mm][Ee]:\\s*(.+)" line))) (and m (string=? (string-trim (list-ref m 1)) name) (< (+ i 1) total) - (org-block-begin? (list-ref lines (+ i 1)))))) + (org-block-begin? (vector-ref lines (+ i 1)))))) ;; Found it — extract body (let ((begin-line (+ i 1))) (let body-loop ((j (+ begin-line 1)) (acc '())) (cond ((>= j total) (string-join (reverse acc) "\n")) - ((org-block-end? (list-ref lines j)) + ((org-block-end? (vector-ref lines j)) (string-join (reverse acc) "\n")) - (else (body-loop (+ j 1) (cons (list-ref lines j) acc))))))) + (else (body-loop (+ j 1) (cons (vector-ref lines j) acc))))))) (else (loop (+ i 1))))))) ;;;============================================================================