~cytrogen/.emacs.d

ref: 504e0080a3f94c9824ac305b1a24b30c7d1fb051 .emacs.d/config/pkg-writing.el -rw-r--r-- 5.2 KiB
504e0080 — HallowDem feat: 添加博客图片插入功能 3 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
;;; pkg-writing.el --- Writing and blogging tools -*- lexical-binding: t -*-

;; Copyright (C) 2024 Cytrogen

;; This file contains:
;; - ox-hugo configuration for blog publishing
;; - YASnippet for text expansion
;; - Newsletter generation tools
;; - Writing-related utilities

;;; Commentary:

;; Tools and configurations specifically for writing, blogging, and content creation.
;; Includes Hugo integration and custom newsletter generation functions.

;;; Code:

;; Ox-Hugo Configuration
;; Blog publishing with Hugo
(unless (package-installed-p 'ox-hugo)
  (package-refresh-contents)
  (package-install 'ox-hugo))

(with-eval-after-load 'ox
  (require 'ox-hugo)
  (setq org-hugo-base-dir "~/Projects/blog"))

;; Universal Elisp Tags Filter
;; Support for Hexo-style block tags
(with-eval-after-load 'ox
  (defun my/org-export-hexo-universal-block (block backend info)
    (when (org-export-derived-backend-p backend 'md)
      (let* ((type (downcase (org-element-property :type block)))
         (content (org-export-data (org-element-contents block) info)))
	(format "{%% %s %%}\n%s{%% end%s %%}" type content type))))
  (add-to-list 'org-export-filter-special-block-functions 'my/org-export-hexo-universal-block))

;; YASnippet Configuration
;; Text expansion system
(unless (package-installed-p 'yasnippet)
  (package-install 'yasnippet))

(with-eval-after-load 'yasnippet
  (yas-global-mode 1)
  (yas-reload-all))

;; Newsletter Tools
;; Custom functions for newsletter generation
(defun my/slugify-title (title)
  "Convert title to anchor-compatible slug, similar to the nodejs script."
  (let ((slug title))
    ;; Remove 《》 brackets
    (setq slug (replace-regexp-in-string "《\\|》" "" slug))
    ;; Remove punctuation, keep Unicode letters, numbers, spaces, hyphens
    (setq slug (replace-regexp-in-string "[^[:alnum:]\\s-]" "" slug))
    ;; Replace spaces with hyphens  
    (setq slug (replace-regexp-in-string "\\s+" "-" slug))
    ;; Convert to lowercase
    (downcase slug)))

(defun my/generate-newsletter-toc ()
  "Generate TOC for newsletter, similar to the nodejs script."
  (interactive)
  (save-excursion
    (goto-char (point-min))
    
    ;; Find the end of details block
    (if (not (re-search-forward "#+END_details" nil t))
        (message "Error: Could not find #+END_details block")
      
      (let ((toc-sections '())
            (current-section nil))
        
        ;; Parse content after the details block
        (while (not (eobp))
          (beginning-of-line)
          (let ((line (thing-at-point 'line t)))
            (cond
             ;; Match H2 headings (exported as ## in markdown)
             ((string-match "^\\* \\(.*\\)$" line)
              (let ((section-title (match-string 1 line)))
                (setq current-section (list :title section-title :articles '()))
                (push current-section toc-sections)))
             
             ;; Match H4 headings with article links (exported as #### [...](url))
             ((and current-section 
                   (string-match "^\\*\\*\\*\\* \\[\\[.*?\\]\\[《\\(.*?\\)》\\]\\]" line))
              (let ((article-title (match-string 1 line)))
                (push article-title (plist-get current-section :articles))))))
          (forward-line 1))
        
        ;; Reverse to get correct order
        (setq toc-sections (reverse toc-sections))
        (dolist (section toc-sections)
          (setq section (plist-put section :articles (reverse (plist-get section :articles)))))
        
        ;; Generate TOC markdown
        (let ((toc-content "\n## 输入\n\n"))
          (dolist (section toc-sections)
            (let ((section-title (plist-get section :title))
                  (articles (plist-get section :articles)))
              (when articles
                (setq toc-content 
                      (concat toc-content 
                              (format "### %s\n\n" section-title)))
                (dolist (article articles)
                  (let ((display-title article)
                        (anchor (my/slugify-title article)))
                    (setq toc-content 
                          (concat toc-content 
                                  (format "- [%s](#%s)\n" display-title anchor))))
                (setq toc-content (concat toc-content "\n")))))
          
          ;; Find the details block and replace its content
          (goto-char (point-min))
          (if (re-search-forward "#+BEGIN_details 本期导读" nil t)
              (progn
                (forward-line 4) ; Skip PROPERTIES block
                (let ((start (point)))
                  (if (re-search-forward "#+END_details" nil t)
                      (progn
                        (beginning-of-line)
                        (delete-region start (point))
                        (insert toc-content)
                        (message "Newsletter TOC generated and inserted!"))
                    (message "Error: Could not find #+END_details"))))
            (message "Error: Could not find details block"))))))))

;; Writing Utilities
;; Additional writing helper functions
(defun my/insert-newsletter-toc ()
  "Deprecated: Use my/generate-newsletter-toc instead."
  (interactive)
  (message "Please use M-x my/generate-newsletter-toc instead."))

(provide 'pkg-writing)
;;; pkg-writing.el ends here