Skip to content

Latest commit

 

History

History
526 lines (478 loc) · 22.4 KB

main.org

File metadata and controls

526 lines (478 loc) · 22.4 KB

Service code

Extracting DRAWERs

(defun extract-drawer-contents (drawer-name &optional pos)
  "Extract the contents of the specified DRAWER from the current heading."
  (org-with-point-at (if pos
                         pos
                       (org-entry-beginning-position))
    (when (re-search-forward (format ":%s:" drawer-name)
                             (org-entry-end-position)
                             t)
      (let* ((drawer-start (match-end 0)))
        (org-with-point-at drawer-start
          (when (re-search-forward ":END:"
                                   (org-entry-end-position)
                                   t)
            (let ((drawer-end (- (match-end 0) 5)))
              (let ((result (buffer-substring drawer-start drawer-end)))
                (when result
                  (split-string (string-trim result) "\n"))))))))))

Getting src-block and xml-parsing

<root>
  <element1>Value 1</element1>
  <element2>Value 2</element2>
</root>
(defun get-named-src-block-content (block-name)
  (let ((block-content nil))
    (org-element-map (org-element-parse-buffer) 'src-block
      (lambda (src-block)
        (when (string= (org-element-property :name src-block) block-name)
          (setq block-content
                (org-element-property :value src-block)))))
    block-content))

(let ((xml (get-named-src-block-content "xml_example")))
  (when (libxml-available-p)
    (with-temp-buffer
      (insert xml)
      (libxml-parse-html-region (point-min) (point-max)))))

;; (defun read-xml-file-and-parse (filename)
;;   "Read the contents of a file into a string."
;;   (with-temp-buffer
;;     (insert-file-contents filename)
;;     (libxml-parse-html-region (point-min) (point-max))))

;; (read-xml-file-and-parse "one.graphml")
(require 'dom2)

(defun sep (msg)
  (replace-regexp-in-string "::" ":•" msg))

(sep "« e0 | #s(gedge n0::n1 n2::n0 #000000 line create-campaign)")

(defun read-xml-file-and-parse (filename)
  "Read the contents of a file into a string."
  (with-temp-buffer
    (insert-file-contents filename)
    (goto-char (point-min))
    (while (re-search-forward "</y:" nil t)
      (replace-match "</" nil nil))
    (goto-char (point-min))
    (while (re-search-forward "<y:" nil t)
      (replace-match "<" nil nil))
    (libxml-parse-html-region (point-min) (point-max))))

;; (message "%s" (read-xml-file-and-parse "one.graphml"))

(cl-defstruct ggroup
  id
  label
  prelist)

(defun parse-groups (nodes)
  (let* ((hash-groups (make-hash-table :test 'equal)))
    (dolist (node nodes nil)
      (let* ((attrs (dom-element-attributes node))
             (node-id (block node-id-block
                        (dolist (attr attrs nil)
                          (when (string= "id" (dom-attr-name attr))
                            ;; (message "= %s : %s"
                            ;;          (dom-attr-name attr)
                            ;;          (dom-attr-value attr))
                            (return-from node-id-block
                              (dom-attr-value attr))))
                        (error "GroupNode does not have id attribute!")))
             (childs (dom-element-child-nodes node))
             (ggroup (make-ggroup)))
        (dolist (child childs nil)
          (when (and (string= "data" (dom-element-name child))
                     (dom-element-has-child-nodes child))
            (let ((data-childs (dom-element-child-nodes child)))
              (dolist (data-ch data-childs nil)
                (when (string= "proxyautoboundsnode" (dom-element-name data-ch))
                  (let ((pabn-childs (dom-element-child-nodes data-ch)))
                    (dolist (pabn-ch pabn-childs nil)
                      (when (string= "realizers" (dom-element-name pabn-ch))
                        (let* ((group-node (dom-element-first-child pabn-ch))
                               (group-node-childs (dom-element-child-nodes group-node)))
                          (dolist (gn-ch group-node-childs nil)
                            (when (string= "nodelabel" (dom-element-name gn-ch))
                              ;; (message "--%s" (dom-element-text-content gn-ch))
                              (setf (ggroup-label ggroup)
                                    (dom-element-text-content gn-ch))
                              ))))))))))
          (when (string= "graph" (dom-element-name child))
            (let* ((attrs (dom-element-attributes child))
                   (node-id (block node-id-block
                              (dolist (attr attrs nil)
                                (when (string= "id" (dom-attr-name attr))
                                  ;; (message "= %s : %s"
                                  ;;          (dom-attr-name attr)
                                  ;;          (dom-attr-value attr))
                                  (return-from node-id-block
                                    (dom-attr-value attr))))
                              (error "Graph does not have id attribute!"))))
              (cl-labels ((pre (node)
                               (let ((parent (dom-node-parent-node node)))
                                 (when parent
                                   (let ((name (dom-node-name node)))
                                     (when (string= "graph" name)
                                       (let ((attrs (dom-node-attributes node)))
                                         (dolist (attr attrs nil)
                                           (when (string= "id" (dom-attr-name attr))
                                             (push (dom-attr-value attr)
                                                   (ggroup-prelist ggroup))))))
                                     (pre parent))))))
                (pre child)
                (setf (ggroup-prelist ggroup)
                      (butlast (ggroup-prelist ggroup))))
              (setf (ggroup-id ggroup)
                    node-id))))
        (puthash (ggroup-id ggroup) ggroup hash-groups)))
    hash-groups))

(cl-defstruct gnode
  geom-x
  geom-y
  fill-color
  label
  shape-type
  prelist)

(defun parse-shapenodes (nodes)
  (let* ((hash-nodes (make-hash-table :test 'equal)))
    (dolist (node nodes nil)
      (let* ((parent-attributes (dom-element-attributes
                                 (dom-element-parent-node
                                  (dom-element-parent-node node))))
             (node-id (block node-id-block
                        (dolist (attr parent-attributes nil)
                          (when (string= "id" (dom-attr-name attr))
                            ;; (message "= %s : %s"
                            ;;          (dom-attr-name attr)
                            ;;          (dom-attr-value attr))
                            (return-from node-id-block
                              (dom-attr-value attr))))
                        (error "Parent Node does not have id attribute!")))
             (childs (dom-element-child-nodes node))
             (gnode (make-gnode)))
        (cl-labels ((pre (node)
                         (let ((parent (dom-node-parent-node node)))
                           (when parent
                             (let ((name (dom-node-name node)))
                               (when (string= "graph" name)
                                 (let ((attrs (dom-node-attributes node)))
                                   (dolist (attr attrs nil)
                                     (when (string= "id" (dom-attr-name attr))
                                       (push (dom-attr-value attr)
                                             (gnode-prelist gnode))))))
                               (pre parent))))))
          (pre node))
        (dolist (child childs nil)
          (when (string= "geometry" (dom-element-name child))
            (let ((child-attr-s (dom-element-attributes child)))
              (dolist (attr child-attr-s nil)
                (when (string= "x" (dom-attr-name attr))
                  (setf (gnode-geom-x gnode) (dom-attr-value attr)))
                (when (string= "y" (dom-attr-name attr))
                  (setf (gnode-geom-y gnode) (dom-attr-value attr))))))
          (when (string= "fill" (dom-element-name child))
            (let ((child-attr-s (dom-element-attributes child)))
              (dolist (attr child-attr-s nil)
                (when (string= "color" (dom-attr-name attr))
                  (setf (gnode-fill-color gnode) (dom-attr-value attr))))))
          (when (string= "nodelabel" (dom-element-name child))
            (setf (gnode-label gnode) (dom-element-text-content child)))
          (when (string= "shape" (dom-element-name child))
            (let ((child-attr-s (dom-element-attributes child)))
              (dolist (attr child-attr-s nil)
                (when (string= "type" (dom-attr-name attr))
                  (setf (gnode-shape-type gnode) (dom-attr-value attr))))))
          (puthash node-id gnode hash-nodes))))
    hash-nodes))

(cl-defstruct gedge
  source
  target
  line-color
  line-type
  label)

(defun parse-edges (edges)
  (let* ((hash-edges (make-hash-table :test 'equal)))
    (dolist (edge edges nil)
      (let* ((parent-attributes (dom-element-attributes
                                 (dom-element-parent-node
                                  (dom-element-parent-node edge))))
             (edge-id)
             (childs (dom-element-child-nodes edge))
             (gedge (make-gedge)))
        (dolist (attr parent-attributes nil)
          (when (string= "id" (dom-attr-name attr))
            (setq edge-id (dom-attr-value attr)))
          (when (string= "source" (dom-attr-name attr))
            (setf (gedge-source gedge) (dom-attr-value attr)))
          (when (string= "target" (dom-attr-name attr))
            (setf (gedge-target gedge) (dom-attr-value attr))))
        (dolist (child childs nil)
          (when (string= "linestyle" (dom-element-name child))
            (let ((child-attr-s (dom-element-attributes child)))
              (dolist (attr child-attr-s nil)
                (when (string= "color" (dom-attr-name attr))
                  (setf (gedge-line-color gedge) (dom-attr-value attr)))
                (when (string= "type" (dom-attr-name attr))
                  (setf (gedge-line-type gedge) (dom-attr-value attr))))))
          (when (string= "edgelabel" (dom-element-name child))
            (setf (gedge-label gedge) (dom-element-text-content child))))
        (puthash edge-id gedge hash-edges)))
    hash-edges))

(defun parse-graphml (filename)
  (let* ((xml   (read-xml-file-and-parse filename))
         (dom   (dom-make-document-from-xml xml))
         (shape-nodes (dom-document-get-elements-by-tag-name dom "shapenode"))
         (hash-nodes (parse-shapenodes shape-nodes))
         (edges (dom-document-get-elements-by-tag-name dom "quadcurveedge"))
         (hash-edges (parse-edges edges))
         (nodes (dom-document-get-elements-by-tag-name dom "node"))
         (groups (remove-if-not
                  (lambda (node)
                    (block filter-block
                      (let ((attrs (dom-element-attributes node)))
                        (when attrs
                          (dolist (attr attrs nil)
                            (when (and (string= "yfiles.foldertype" (dom-attr-name attr))
                                       (string= "group" (dom-attr-value attr)))
                              (return-from filter-block t)))))))
                  nodes))
         (hash-groups (parse-groups groups)))
    (values hash-nodes
            hash-edges
            hash-groups)))

;; test
(multiple-value-bind (hash-nodes hash-edges hash-groups)
    (parse-graphml "five.graphml")
  (maphash
   (lambda (key value)
     (princ (sep (format "» %s | %s\n" key value))))
   hash-nodes)
  (maphash
   (lambda (key value)
     (princ (sep (format "« %s | %s\n" key value))))
   hash-edges)
  (maphash
   (lambda (key value)
     (princ (sep (format "¤ %s | %s\n" key value))))
   hash-groups))

Finding FLOWs

(defun find-flow-elts ()
  "Внутри текущего org-entry находит все flow-elts в кавычках-елочках"
  (let ((line-regexp "«.*?»")
        (found-list))
    (while (re-search-forward line-regexp (org-entry-end-position) t)
      (pushnew (buffer-substring-no-properties (+ (match-beginning 0) 1)
                                               (- (match-end 0) 1))
               found-list))
    (reverse found-list)))

(defun find-all-flows ()
  "Для всех org-entry, имеющих propety FLOW:t, возвращает список из двух элементов, первый из которых является заголовком, а второй - списком найденных flow-elts в кавычках-елочках"
  (let ((return-list))
    (org-map-entries
     (lambda ()
       (when (string= (org-entry-get nil "FLOW") t)
         (push (list (format "%s" (nth 4 (org-heading-components)))
                     (find-flow-elts))
               return-list)))
     nil 'file)
    (reverse return-list)))

;; (find-all-flows)

(cl-defstruct gfun ;; Структура flow-функции
  source
  target
  ;; src-id
  ;; trg-id
  fnname
  params
  return)

(defun find-flows-with-params-and-returns (flows)
  "Для всех flow преобразует списки flow-elts в структуры gfun, для чего ищет в org-файле разделы с такими же именами и извлекает из них property PARAMS и RETURN. Получается список из двух элементов, где первый - название flow, а второй - список структур gfun, каждая из которых имеет fname и может иметь заполненные params и return"
  (mapcar
   (lambda (flow)
     (destructuring-bind (flow-name fns) flow
       (list
        flow-name
        (let ((new-fns))
          (mapcar
           (lambda (fn)
             (org-map-entries
              (lambda ()
                (let ((heading (org-get-heading 'no-tags)))
                  (when (equal fn heading)
                    (push
                     (make-gfun :fnname fn
                                :params (org-entry-get nil "PARAMS")
                                :return (org-entry-get nil "RETURN"))
                     new-fns))))
              nil 'file))
           fns)
          (reverse new-fns)))))
   flows))

;; (find-flows-with-params-and-returns (find-all-flows))

(defun find-flows-enrich-edges (flows-with-params-and-returns hash-edges)
  "Для всех flow в каждой из структур gfun заполняет поля source и target если находит соответствующий элемент в hash-edges"
  (mapcar
   (lambda (flow)
     (destructuring-bind (flow-name fns) flow
       (list
        flow-name
        (let ((new-fns))
          (mapcar
           (lambda (fn)
             (maphash
              (lambda (key value)
                (when (string= (gedge-label value) (gfun-fnname fn))
                  (let ((etrg (gedge-target value))
                        (esrc (gedge-source value)))
                    ;; (setf (gfun-trg-id fn) etrg)
                    ;; (setf (gfun-src-id fn) esrc)
                    (setf (gfun-target fn)
                          (gnode-label (gethash etrg hash-nodes)))
                    (setf (gfun-source fn)
                          (gnode-label (gethash esrc hash-nodes))))))
              hash-edges)
             (push fn new-fns))
           fns)
          (reverse new-fns)))))
   flows-with-params-and-returns))

(defun get-all-gfuns (hash-edges)
  "Собирает список всех gfun"
  (let ((funs))
    (dolist (flow (find-flows-enrich-edges
                   (find-flows-with-params-and-returns (find-all-flows))
                   hash-edges))
      (dolist (fn (cadr flow))
        (push fn funs)))
    funs))

(defun group-gfuns-by-target (gfuns)
  "Группирует gfun в список из двух элементов, первый из которых - target, а второй - список gfun которые имеют этот target"
  (let ((hash (make-hash-table :test #'equal))
        (result))
    (dolist (gfun gfuns)
      (let ((target (gfun-target gfun)))
        (when target
          (let ((old (gethash target hash)))
            (if old
                (puthash target
                         (append old (list gfun))
                         hash)
              (puthash target
                       (list gfun)
                       hash))))))
    (maphash (lambda (key value)
               (push (list key value) result))
             hash)
    result))

(multiple-value-bind (hash-nodes hash-edges hash-groups)
    (parse-graphml "five.graphml")
  (group-gfuns-by-target
   (get-all-gfuns hash-edges)))

Replacing src-blocks

(defun replace-named-src-block-content (block-name new-content)
  "Replace the content of a named source block while maintaining document structure."
  (let ((org-buffer (current-buffer)))
    (org-element-map (org-element-parse-buffer) 'src-block
      (lambda (src-block)
        (when (string= (org-element-property :name src-block) block-name)
          (let* ((begin (org-element-property :begin src-block))
                 (end (org-element-property :end src-block))
                 (new `(:name ,block-name :value ,new-content
                              :language "xml")))
            (save-excursion
              (goto-char begin)
              (delete-region begin end)
              (insert
               (org-element-interpret-data
                (org-element-create 'src-block new)))
              (set-buffer-modified-p nil)
              (message "Content of named block %s replaced" block-name)
              (throw 'block-found t))))))))

(let* ((block-name "xml_replace")
       (new-content "<html>\n<body>\n</body>\n<html>\n"))
  (condition-case nil
      (replace-named-src-block-content block-name new-content)
    (error (message "Named block %s not found" block-name))))

Этот блок будет заменен вышеприведенным кодом, при его исполнении

<root>
  <element1>Value 1</element1>
  <element2>Value 2</element2>
</root>

Button overlay

(defun my-button-action ()
  "Action to be executed when the button is activated."
  (interactive)
  (message "Button pressed!"))

(defun ignore-modification (ol1 after beg end &optional _len)
  (error "non-modify-button!"))

(defun create-improvised-button (start end)
  "Create an improvised button between START and END."
  (let ((button-overlay (make-overlay start end)))
    (overlay-put button-overlay 'face '(:foreground "blue" :underline t))
    (overlay-put button-overlay 'mouse-face 'highlight)
    ;; (overlay-put button-overlay
    ;;              'modification-hooks '(ignore-modification))
    (overlay-put button-overlay
                 'keymap (let ((map (make-sparse-keymap)))
                           (define-key map [mouse-1] 'my-button-action)
                           (define-key map (kbd "RET") 'my-button-action)
                           map))))

(defun setup-improvised-buttons ()
  "Set up improvised buttons in the buffer."
  (interactive)
  (save-excursion
    (goto-char (point-min))
    (while (re-search-forward
            (format "%s%s" "Click " "here to execute code")
            nil t)
      (let ((begin (match-beginning 0))
            (end (match-end 0)))
        (message "%s : %s" begin end)
        (create-improvised-button begin end)))))

;; Применяем настройку кнопок
(setup-improvised-buttons)

Here is overlay button:

  • Click here to execute code