diff options
| author | Craig Jennings <c@cjennings.net> | 2026-02-14 00:06:45 -0600 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-02-14 00:06:45 -0600 |
| commit | 78c3ef3c2008f72f9e46f30447c68d627bd693cd (patch) | |
| tree | 9d4cc7f523db907c7bdf99e654cd1ca47b2f8551 /modules/hugo-config.el | |
| parent | 48a2d4cc31b2825b39d5efdf619189c23c55a659 (diff) | |
feat(hugo): extract hugo-config module with C-; h keybindings
Standalone module for ox-hugo blog workflow. One-file-per-post
structure with keybindings for new post, export, open dir (dirvish
and system file manager), and toggle draft.
Diffstat (limited to 'modules/hugo-config.el')
| -rw-r--r-- | modules/hugo-config.el | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/modules/hugo-config.el b/modules/hugo-config.el new file mode 100644 index 00000000..8bc2cef2 --- /dev/null +++ b/modules/hugo-config.el @@ -0,0 +1,124 @@ +;;; hugo-config.el --- Hugo Blog Configuration -*- lexical-binding: t; coding: utf-8; -*- +;; author: Craig Jennings <c@cjennings.net> + +;;; Commentary: +;; Integrates ox-hugo for publishing Org files to a Hugo website. +;; +;; One-file-per-post workflow: +;; - Each blog post is a standalone Org file in content-org/log/ +;; - File-level keywords control Hugo front matter +;; - Export with C-; h e, create new posts with C-; h n +;; +;; Keybindings (C-; h prefix): +;; - C-; h n : New post (create from template) +;; - C-; h e : Export current post to Hugo markdown +;; - C-; h o : Open blog source directory in dirvish +;; - C-; h O : Open blog source directory in system file manager +;; - C-; h d : Toggle draft status (TODO/DONE) + +;;; Code: + +(require 'user-constants) +(require 'host-environment) + +;; --------------------------------- Constants --------------------------------- + +(defconst cj/hugo-content-org-dir + (expand-file-name "content-org/log/" website-dir) + "Directory containing Org source files for Hugo blog posts.") + +;; ---------------------------------- ox-hugo ---------------------------------- + +(use-package ox-hugo + :after ox) + +;; ----------------------------- Hugo Blog Functions --------------------------- + +(defun cj/hugo-new-post () + "Create a new Hugo blog post as a standalone Org file. +Prompts for title, generates the slug filename, and opens the +new file with Hugo front matter keywords pre-filled." + (interactive) + (require 'ox-hugo) + (let* ((title (read-from-minibuffer "Post Title: ")) + (slug (org-hugo-slug title)) + (date (format-time-string "%Y-%m-%d")) + (file (expand-file-name (concat slug ".org") cj/hugo-content-org-dir))) + (when (file-exists-p file) + (user-error "Post already exists: %s" file)) + (unless (file-directory-p cj/hugo-content-org-dir) + (make-directory cj/hugo-content-org-dir t)) + (find-file file) + (insert (format "#+hugo_base_dir: ../../ +#+hugo_section: log +#+hugo_auto_set_lastmod: t +#+title: %s +#+date: %s +#+hugo_tags: +#+hugo_draft: true +#+hugo_custom_front_matter: :description \"\" + +" title date)) + (save-buffer) + (message "New post: %s" file))) + +(defun cj/hugo-export-post () + "Export the current Org file to Hugo-compatible Markdown." + (interactive) + (require 'ox-hugo) + (unless (derived-mode-p 'org-mode) + (user-error "Not in an Org buffer")) + (org-hugo-export-to-md) + (message "Exported: %s" (buffer-name))) + +(defun cj/hugo-open-blog-dir () + "Open the blog source directory in dirvish/dired." + (interactive) + (unless (file-directory-p cj/hugo-content-org-dir) + (make-directory cj/hugo-content-org-dir t)) + (dired cj/hugo-content-org-dir)) + +(defun cj/hugo-open-blog-dir-external () + "Open the blog source directory in the system file manager." + (interactive) + (unless (file-directory-p cj/hugo-content-org-dir) + (make-directory cj/hugo-content-org-dir t)) + (let ((cmd (cond + ((env-macos-p) "open") + ((env-windows-p) "explorer.exe") + (t "xdg-open")))) + (start-process "hugo-file-manager" nil cmd cj/hugo-content-org-dir))) + +(defun cj/hugo-toggle-draft () + "Toggle the draft status of the current Hugo post. +Switches #+hugo_draft between true and false." + (interactive) + (save-excursion + (goto-char (point-min)) + (if (re-search-forward "^#\\+hugo_draft: *\\(true\\|false\\)" nil t) + (let ((current (match-string 1))) + (replace-match (if (string= current "true") "false" "true") t t nil 1) + (save-buffer) + (message "Draft: %s → %s" current + (if (string= current "true") "false" "true"))) + (user-error "No #+hugo_draft keyword found in this file")))) + +;; -------------------------------- Keybindings -------------------------------- + +(global-set-key (kbd "C-; h n") #'cj/hugo-new-post) +(global-set-key (kbd "C-; h e") #'cj/hugo-export-post) +(global-set-key (kbd "C-; h o") #'cj/hugo-open-blog-dir) +(global-set-key (kbd "C-; h O") #'cj/hugo-open-blog-dir-external) +(global-set-key (kbd "C-; h d") #'cj/hugo-toggle-draft) + +(with-eval-after-load 'which-key + (which-key-add-key-based-replacements + "C-; h" "hugo blog menu" + "C-; h n" "new post" + "C-; h e" "export post" + "C-; h o" "open in dirvish" + "C-; h O" "open in file manager" + "C-; h d" "toggle draft")) + +(provide 'hugo-config) +;;; hugo-config.el ends here |
