ฉันจะเดินแผนผังองค์กรโหมดได้อย่างไร


10

พื้นหลัง

ฉันกำลังเขียนโหมดการนำเสนอสำหรับ Emacs ฉันต้องการให้อินพุตเป็นไฟล์ org เนื่องจากไฟล์ org นั้นยอดเยี่ยมสำหรับข้อมูล

ปัญหา

ฉันต้องแปลงไฟล์โหมด org เป็นรายการของโครงสร้างข้อมูล "ภาพนิ่ง" ที่ฉันสามารถทำซ้ำได้ ในการทำเช่นนี้ฉันต้องการทำบางสิ่งเช่นไฟล์โหมด org ต่อไปนี้:

* this is the first headline, with a title property and no contents
* this is the second headline, with contents
- dash list nested under the second headline
  - further nested
** nested headline

และสามารถเดินได้ ฉันลอง(org-element-parse-buffer)แล้วและนั่นก็ให้รายการองค์ประกอบแก่ฉัน แต่ก็ยากที่จะเข้าใจว่าจะเดินต่อไปได้อย่างไร ตัวอย่างเช่นการโทร(org-element-map (org-element-parse-buffer) 'headline #'identity)ให้รายการของสามองค์ประกอบ อันสุดท้ายแสดงถึง "พาดหัวซ้อนกัน" ฉันต้องการให้ "พาดหัวซ้อนกัน" เป็นลูกของ "นี่คือพาดหัวที่สองพร้อมเนื้อหา"

หลีกเลี่ยงปัญหา XY

แน่นอนว่าฉันจะเปิดวิธีอื่นในการแปลงไฟล์โหมด org เป็นโครงสร้างข้อมูล Elisp ฉันไม่คิดว่า org-export เป็นเครื่องมือที่เหมาะสมสำหรับฉันเพราะฉันไม่ต้องการที่จะจบลงด้วยไฟล์ใหม่ที่มีผลลัพธ์ แต่โครงสร้างข้อมูลที่ฉันสามารถทำซ้ำได้ วิธีที่ไร้เดียงสาของฉันคือบางสิ่งเช่น "ให้ฉันพาดหัวข่าวระดับบนสุดทั้งหมดจากนั้นฉันจะได้รับคุณสมบัติและองค์ประกอบที่มีอยู่ (เช่นข้อความธรรมดาหรือรายการซ้อน - ไม่ว่าจะเป็นพาดหัวข่าวหรือรายการเส้นประอื่น ๆ ")


2
ฉันเชื่อว่าอาร์กิวเมนต์ตัวเลือกที่สามno-recursionของorg-element-mapควรทำสิ่งที่คุณต้องการ
wvxvw

2
ลองไปที่ด้านล่างของไฟล์แล้วค้นหาย้อนกลับเพื่อมุ่งหน้าคว้าทุกอย่างแล้วทำต่อไป - ทำซ้ำกระบวนการ - จนกว่าคุณจะถึงด้านบนของไฟล์จากนั้นจึงโยนทิ้ง เราย้อนกลับเพราะจุดอยู่ที่จุดเริ่มต้นของส่วนหัวหลังจากการค้นหาแต่ละครั้งดังนั้นจึงมีประสิทธิภาพมากกว่าการไปข้างหน้าแล้วย้อนกลับไปเล็กน้อยเพื่อเป็นจุดเริ่มต้นของส่วนหัว นี่คือวิธีการทำงานของวาระการประชุม - เช่นรายการ org- ระเบียบวาระการประชุม, org-search-view, org-tags-view
กฎหมาย

คำตอบ:


7

ฉันมีปัญหาที่คล้ายกันดังนั้นอาจจะช่วยได้ - ฉันไม่คุ้นเคยกับการส่งออก org หรือ internals ภายใน แต่ฉันไม่พบสิ่งใดที่จะแยกไฟล์ org ไปยังโครงสร้างต้นไม้ แต่ให้บัฟเฟอร์เหมือน

* england
** london
** bristol
* france

มันจะให้คุณ

(org-get-header-tree) => ("england" ("london" "bristol") "france")

และสามารถรวมข้อมูลอื่น ๆ จากต้นไม้เช่นกัน


เมื่อได้รับรายการระดับที่คงที่เราต้องสร้างต้นไม้เช่น (1 1 2 3 1) => (1 1 (2 (3)) 1) ฉันไม่สามารถหาฟังก์ชั่นที่จะทำสิ่งนี้ได้ดังนั้นจึงต้องเขียนเซลล์ข้อเสียหนึ่งครั้งหลังจากนั้นฉันแน่ใจว่ามีวิธีที่ดีกว่าในการทำสิ่งนี้ แต่มันใช้งานได้ ฟังก์ชั่นนี้unflattenใช้ฟังก์ชั่นลิสต์แบบแบนและฟังก์ชั่นสองสามอย่างในการดึงข้อมูลที่คุณต้องการจากรายการและระดับรายการและสร้างโครงสร้างแบบต้นไม้

ในorg-get-header-listคุณสามารถเพิ่มข้อมูลเพิ่มเติมที่คุณต้องการแยกจากแต่ละรายการที่มีการโทรorg-element-propertyแล้วในนั้นorg-get-header-treeคุณสามารถรวมฟังก์ชั่นเพื่อดึงข้อมูลจากรายการ

เนื่องจากมันไม่รวมถึงการจัดการรายการ dash แต่บางทีมันอาจถูกดัดแปลงเพื่อจัดการกับรายการเหล่านั้นโดยไม่มีปัญหามากเกินไป ...


(defun unflatten (xs &optional fn-value fn-level)
  "Unflatten a list XS into a tree, e.g. (1 2 3 1) => (1 (2 (3)) 1).
FN-VALUE specifies how to extract the values from each element, which
are included in the output tree, FN-LEVEL tells how to extract the
level of each element. By default these are the `identity' function so
it will work on a list of numbers."
  (let* ((level 1)
         (tree (cons nil nil))
         (start tree)
         (stack nil)
         (fn-value (or fn-value #'identity))
         (fn-level (or fn-level #'identity)))
    (dolist (x xs)
      (let ((x-value (funcall fn-value x))
            (x-level (funcall fn-level x)))
        (cond ((> x-level level)
               (setcdr tree (cons (cons x-value nil) nil))
               (setq tree (cdr tree))
               (push tree stack)
               (setq tree (car tree))
               (setq level x-level))
              ((= x-level level)
               (setcdr tree (cons x-value nil))
               (setq tree (cdr tree)))
              ((< x-level level)
               (while (< x-level level)
                 (setq tree (pop stack))
                 (setq level (- level 1)))
               (setcdr tree (cons x-value nil))
               (setq tree (cdr tree))
               (setq level x-level)))))
      (cdr start)))

; eg (unflatten '(1 2 3 2 3 4)) => '(1 (2 (3) 2 (3 (4))))


(defun org-get-header-list (&optional buffer) 
  "Get the headers of an org buffer as a flat list of headers and levels.
Buffer will default to the current buffer."
  (interactive)
  (with-current-buffer (or buffer (current-buffer))
    (let ((tree (org-element-parse-buffer 'headline)))
      (org-element-map 
          tree 
          'headline
        (lambda (el) (list 
                 (org-element-property :raw-value el) ; get header title without tags etc
                 (org-element-property :level el) ; get depth
                 ;; >> could add other properties here
                 ))))))

; eg (org-get-header-list) => (("pok" 1) ("lkm" 1) (("cedar" 2) ("yr" 2)) ("kjn" 1))


(defun org-get-header-tree (&optional buffer)
  "Get the headers of the given org buffer as a tree."
  (interactive)
  (let* ((headers (org-get-header-list buffer))
         (header-tree (unflatten headers  
                 (lambda (hl) (car hl))  ; extract information to include in tree
                 (lambda (hl) (cadr hl)))))  ; extract item level
    header-tree))

; eg (org-get-header-tree) => ("pok" "lkm" ("cedar" "yr") "kjn")
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.