Kuruluş modu ağacında nasıl yürüyebilirim?


10

Arka fon

Emacs için bir sunum modu yazıyorum. Org dosyaları veriler için harika olduğundan girdinin org dosyaları olmasını istiyorum.

Sorun

Kuruluş modu dosyasını, yineleyebileceğim "slayt" veri yapılarının bir listesine dönüştürmek zorundayım. Bunu yapmak için, aşağıdaki kuruluş modu dosyası gibi bir şey almak istiyorum:

* 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

ve yürüyebiliyorlar. Denedim (org-element-parse-buffer)ve bu bana bir öğe listesi veriyor, ancak onlarda nasıl daha fazla yürüyeceğinizi anlamak zor. Örneğin, arama üç öğenin (org-element-map (org-element-parse-buffer) 'headline #'identity)bir listesini verir ; sonuncusu "iç içe başlığı" temsil eder. "İç içe başlık" ın "içeriği olan ikinci başlık" ın alt öğesi olmasını istiyorum.

XY probleminden kaçınma

Kesinlikle bir kuruluş modu dosyasını Elisp veri yapısına dönüştürmenin diğer yollarına açığım. Ben yok düşünüyorum ben sonuçlarını içeren yeni bir dosya ile bitirmek istemiyorum çünkü org ihracatı, benim için doğru bir araçtır, ancak bir veri yapısı ı yinelemek. Benim naif yolum "bana tüm üst düzey başlıkları ver ve sonra özelliklerini ve içerdiği öğeleri (örneğin, düz metin veya iç içe listeler - diğer başlıklar veya tire listeleri) olsun" gibi bir şeydir.


2
Üçüncü isteğe bağlı argüman inanıyoruz no-recursionait org-element-mapistediğini yapmalıdır.
wvxvw

2
Dosyanın alt kısmına gidip bir başlık için geriye doğru arama yapmaya, her şeyi yakalamaya ve ardından dosyanın üst kısmına ulaşıncaya kadar işlemi tekrarlamaya devam etmeye devam edin. Geriye doğru gidiyoruz çünkü nokta her aramadan sonra başlığın başında olduğu için, ileriye gitmekten ve daha sonra başlığın başında olmak için biraz geri gitmekten daha verimlidir. Kuruluş gündemi şu şekilde çalışır - ör. Kuruluş-gündem listesi, kuruluş-arama-görünümü, kuruluş-etiketleri-görünümü.
hukukçu

Yanıtlar:


7

Benzer bir sorun vardı, bu yüzden belki bu yardımcı olacaktır - org ihracat veya org iç ile çok aşina değilim, ama bir org dosyasını bir ağaç yapısına ayrıştıracak bir şey bulamadım. Ama tampon gibi

* england
** london
** bristol
* france

sana verecek

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

ve ağaçtan başka bilgiler de içerebilir.


Düz bir seviye listesi verildiğinde, bir ağaç üretmemiz gerekir, örneğin (1 1 2 3 1) => (1 1 (2 (3)) 1). Bunu yapacak bir işlev bulamadım, bu yüzden eksilerini çok fazla çizdikten sonra yazdı - eminim bunu yapmanın daha iyi bir yolu var ama işe yarıyor. İşlev unflatten, listeden ve öğe düzeylerinden istediğiniz bilgileri ayıklamak için düz bir liste ve birkaç işlev alır ve bir ağaç yapısı oluşturur.

İçinde org-get-header-listher öğeden çağrı yapmak istediğinizden daha fazla bilgi ekleyebilir org-element-propertyve ardından org-get-header-treelisteden bilgileri ayıklamak için işlevler ekleyebilirsiniz.

Durduğu gibi bu çizgi listeleri için taşıma içermez, ancak belki de çok fazla sorun olmadan bunları ele almak için uyarlanabilir ...


(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")
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.