├── dokuwiki.el ├── org-blog.el ├── sigdb-mode.el └── blorg.el /dokuwiki.el: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexott/emacs-addons/master/dokuwiki.el -------------------------------------------------------------------------------- /org-blog.el: -------------------------------------------------------------------------------- 1 | ;;; org-blog.el --- 2 | 3 | ;; Copyright (C) Alex Ott 4 | ;; 5 | ;; Author: Alex Ott 6 | ;; Keywords: 7 | ;; Requirements: 8 | ;; Status: not intended to be distributed yet 9 | 10 | 11 | (require 'org-export-generic) 12 | 13 | 14 | (provide 'org-blog) 15 | 16 | 17 | ;;; org-blog.el ends here 18 | -------------------------------------------------------------------------------- /sigdb-mode.el: -------------------------------------------------------------------------------- 1 | ;;; sigdb-mode.el --- 2 | 3 | ;; Copyright (C) Alex Ott 4 | ;; 5 | ;; Author: Alex Ott 6 | ;; Keywords: 7 | ;; Requirements: 8 | ;; Status: not intended to be distributed yet 9 | 10 | ;; (eval-when-compile (require 'cl)) 11 | 12 | (defvar sigdb-font-lock-keywords 13 | ;; The comment syntax can't be described simply in syntax-table. 14 | ;; We could use font-lock-syntactic-keywords, but is it worth it? 15 | '(("^;; .*" . font-lock-comment-face) 16 | ("\\_<\\(description\\|signatures\\|extensions\\|aliases\\|attributes\\)\\_>" 17 | (1 font-lock-keyword-face)) 18 | ("attributes\\s *{\\(\\(stream\\|final\\|document\\|archive\\|image\\|video\\|audio\\|text\\|database\\|executable\\|\\s +\\)*\\)}" 19 | 1 font-lock-constant-face) 20 | ("\\(\\\"[^\"]*\\\"\\)" 1 font-lock-string-face) 21 | ("^\\(#include\\)\\s +\\\"[^\"]*\\\"" 1 font-lock-preprocessor-face) 22 | ("^\\s *\\(\\S +/\\S +\\)" 1 font-lock-type-face) 23 | )) 24 | 25 | ;;;###autoload 26 | (add-to-list 'auto-mode-alist '("\\.sigdb\\'" . sigdb-mode)) 27 | 28 | ;;;###autoload 29 | (define-derived-mode sigdb-mode fundamental-mode "SigDB" 30 | "Major mode for signature database files." 31 | (set (make-local-variable 'font-lock-defaults) 32 | '(sigdb-font-lock-keywords t t nil nil)) 33 | (set (make-local-variable 'comment-start) ";; ") 34 | (set (make-local-variable 'comment-end) "") 35 | (set (make-local-variable 'comment-end-skip) "[ ]*\\(\\s>\\|\n\\)") 36 | ) 37 | 38 | (provide 'sigdb-mode) 39 | 40 | ;;; sigdb-mode.el ends here 41 | -------------------------------------------------------------------------------- /blorg.el: -------------------------------------------------------------------------------- 1 | ;;; blorg.el --- export a blog from an org file 2 | 3 | (defconst blorg-version "0.75e" "`blorg' version.") 4 | 5 | ;; Copyright 2006 Bastien Guerry 6 | ;; 7 | ;; Author: Bastien Guerry 8 | ;; Version: $Id: blorg.el,v 0.67 2008/01/29 14:08:13 guerry Exp guerry $ 9 | ;; Keywords: org-mode blog publishing html feed atom rss 10 | ;; X-URL: 11 | ;; 12 | ;; This file is not part of GNU Emacs. 13 | ;; 14 | ;; This program is free software; you can redistribute it and/or 15 | ;; modify it under the terms of the GNU General Public License as 16 | ;; published by the Free Software Foundation; either version 2, or (at 17 | ;; your option) any later version. 18 | ;; 19 | ;; This program is distributed in the hope that it will be useful, but 20 | ;; WITHOUT ANY WARRANTY; without even the implied warranty of 21 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 22 | ;; General Public License for more details. 23 | ;; 24 | ;; You should have received a copy of the GNU General Public License 25 | ;; along with this program; if not, write to the Free Software 26 | ;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 27 | 28 | ;;; Commentary: 29 | 30 | ;; blorg creates a blog from an org file. Just edit your `org-mode' 31 | ;; buffer then do M-x `blorg-publish'. This is bound to C-c ". 32 | ;; 33 | ;; Here is the list of pages created by `blorg': 34 | ;; 35 | ;; - index page 36 | ;; - atom/rss feed for index page 37 | ;; - tags pages 38 | ;; - atom/rss feeds for tags pages 39 | ;; - months pages 40 | ;; - posts pages 41 | ;; 42 | ;; Each page is rendered with a specific HTML layout. You can change 43 | ;; the layout of all theses pages (and of the post itself) by using 44 | ;; templates. Have a look at M-x customize-group `blorg-templates'. 45 | ;; 46 | ;; If a post or a tag-page already exists, `blorg' won't overwrite it. 47 | ;; To force publishing of all the pages, add a prefix: C-u M-x 48 | ;; `blorg-publish'. 49 | ;; 50 | ;; `blorg' will only publish posts marked with the "DONE" todo 51 | ;; keyword. You can use another string either by explicitely adding 52 | ;; the #+DONE_STRING: option at the beginning of the file or by 53 | ;; changing the last keyword in `org-todo-keywords'. This TODO 54 | ;; keywords are also set by #+SEQ_TODO: in the buffer. 55 | ;; 56 | ;; If the heading of an entry is followed by a CLOSED keyword, 57 | ;; `blorg' will use this date as the publication date. 58 | ;; 59 | ;; If the heading if followed by tags, `blorg' will publish a tag 60 | ;; page for each one of them. 61 | ;; 62 | ;; You can set up a few options, either by customizing the variable 63 | ;; `blorg-default-options' (for all your Org) files or by adding 64 | ;; options at the beginning of the file: 65 | ;; 66 | ;; Main informations: 67 | ;; #+TITLE : the title of your blog 68 | ;; #+SUBTITLE : the subtitle of your blog 69 | ;; #+AUTHOR : the author of the blog 70 | ;; #+EMAIL : the author's e-mail address 71 | ;; #+LANGUAGE : language of the blog 72 | ;; 73 | ;; Publishing options: 74 | ;; #+BLOG_URL : the full url of the blog 75 | ;; #+PUBLISH_DIR : absolute directory name (where to publish files) 76 | ;; #+UPLOAD_DIR : relative upload directory name 77 | ;; #+IMAGES_DIR : relative images directory name 78 | ;; #+CONFIG_FILE : elisp config file for this blog 79 | ;; 80 | ;; Other informations:: 81 | ;; #+CREATED : <%Y-%m-%d> 82 | ;; #+KEYWORDS : global keywords for this blog 83 | ;; #+HOMEPAGE : the author's homepage (not her blog)OB 84 | ;; #+ENCODING : encoding of the blog 85 | ;; #+HTML_CSS : stylesheet URL for html pages 86 | ;; #+XML_CSS : stylesheet URL for xml feeds 87 | ;; #+FEED_TYPE : atom or rss (which is rss 2.0 by default) 88 | ;; #+DONE_STRING : (maybe special) DONE string 89 | ;; 90 | ;; See M-x `customize-group' RET `blorg' for further details. 91 | ;; 92 | 93 | ;; Warning: you should better run `blorg' with the latest 94 | ;; `org-mode' - at least org-mode v4.53. You can get org-mode from 95 | ;; here : 96 | 97 | ;; Put this file into your load-path and the following into your 98 | ;; ~/.emacs: (require 'blorg) 99 | 100 | ;;; Todo: 101 | 102 | ;; See 103 | 104 | ;;; Notes: 105 | 106 | ;;; History: 107 | ;; 108 | ;; First released <2006-06-09 lun> 109 | ;; Started <2006-05-01 lun> 110 | 111 | ;;; Code: 112 | 113 | 114 | ;;; Requirements 115 | (provide 'blorg) 116 | 117 | (require 'org) 118 | (require 'calendar) 119 | (require 'time-stamp) 120 | ;; (require 'eshell) 121 | ;; (require 'em-unix) 122 | 123 | ;; rewrite as below 124 | ;; (when (and 125 | ;; (equal system-type 'darwin) 126 | ;; (string-match (emacs-version) "GNU Emacs 22\\.")) 127 | ;; (require 'esh-maint)) 128 | 129 | ;; Not necessary since emacs 22 130 | (when (< (string-to-number (substring emacs-version 0 2)) 22) 131 | (require 'regexp-opt)) 132 | 133 | ;; XEmacs prior to 21.5 is not dumped with replace-regexp-in-string. In 134 | ;; those cases it can be found in the xemacs-base package. 135 | (eval-and-compile 136 | (unless (and (fboundp 'replace-regexp-in-string) 137 | (not (featurep 'xemacs))) 138 | (require 'easy-mmode)) 139 | (require 'cl)) 140 | 141 | ;;; Make the compiler quiet 142 | ;;; Don't mess around with namespaces 143 | 144 | (defvar blorgv-time-stamp-formats nil) 145 | (defvar blorgv-publish-index-only nil) 146 | (defvar blorgv-tagstotal nil) 147 | (defvar blorgv-tagsaverage nil) 148 | (defvar blorgv-encoding nil) 149 | (defvar blorgv-header nil) 150 | (defvar blorgv-feed-type nil) 151 | (defvar blorgv-feed-file-name nil) 152 | (defvar blorgv-blog-title nil) 153 | (defvar blorgv-post-title nil) 154 | (defvar blorgv-post-rel-url nil) 155 | (defvar blorgv-xml-css nil) 156 | (defvar blorgv-created "") 157 | (defvar blorgv-created-row "") 158 | (defvar blorgv-created-rfc3339 "") 159 | (defvar blorgv-created-rfc822 "") 160 | (defvar blorgv-modified "") 161 | (defvar blorgv-modified-row "") 162 | (defvar blorgv-modified-rfc3339 "") 163 | (defvar blorgv-modified-rfc822 "") 164 | (defvar blorgv-updated "") 165 | (defvar blorgv-published nil) 166 | (defvar blorgv-content nil) 167 | (defvar blorgv-subtitle "") 168 | (defvar blorgv-blog-url "") 169 | (defvar blorgv-done-string "") 170 | (defvar blorgv-keywords "") 171 | (defvar blorgv-language "") 172 | (defvar blorgv-author "") 173 | (defvar blorgv-homepage "") 174 | (defvar blorgv-email "") 175 | (defvar blorgv-ins-full nil) 176 | (defvar blorgv-tags-links nil) 177 | (defvar blorgv-publish-d "~/public_html/") 178 | (defvar blorgv-images-d "upload/") 179 | (defvar blorgv-upload-d "images/") 180 | 181 | ;;; Set aliases, keys, constants, advicest 182 | (define-key org-mode-map "\C-c\"" 'blorg-publish) 183 | 184 | (defconst blorg-generator-url 185 | "http://www.cognition.ens.fr/~guerry/u/blorg.el" 186 | "`blorg' permanent URL.") 187 | 188 | (defconst blorg-generated-by-string 189 | (concat "Done with blorg " blorg-version 190 | " -- org-mode " org-version 191 | " and GNU Emacs " emacs-version)) 192 | 193 | ;; see org-infile-export-plist ? 194 | (defconst blorg-options-regexps-alist 195 | '((:blog-title "^#\\+TITLE:[ \t]+\\(.+\\)$") 196 | (:subtitle "^#\\+SUBTITLE:[ \t]+\\(.+\\)$") 197 | (:author "^#\\+AUTHOR:[ \t]+\\(.+\\)$") 198 | (:email "^#\\+EMAIL:[ \t]+\\(.+\\)$") 199 | (:created "^#\\+CREATED:[ \t]+<\\([^>]+\\)>$") 200 | (:modified "^#\\+Time-stamp:[ \t]+<\\([^>]+\\)>$") 201 | (:blog-url "^#\\+BLOG_URL:[ \t]+\\(.+\\)$") 202 | (:homepage "^#\\+HOMEPAGE:[ \t]+\\(.+\\)$") 203 | (:language "^#\\+LANGUAGE:[ \t]+\\(.+\\)$") 204 | (:encoding "^#\\+ENCODING:[ \t]+\\(.+\\)$") 205 | (:keywords "^#\\+KEYWORDS:[ \t]+\\(.+\\)$") 206 | (:html-css "^#\\+HTML_CSS:[ \t]+\\(.+\\)$") 207 | (:xml-css "^#\\+XML_CSS:[ \t]+\\(.+\\)$") 208 | (:feed-type "^#\\+FEED_TYPE:[ \t]+\\(.+\\)$") 209 | ;; (:seq-todo "^#\\+SEQ_TODO:[ \t]+\\(.+\\)$") 210 | (:done-string "^#\\+DONE_STRING:[ \t]+\\(.+\\)$") 211 | (:publish-dir "^#\\+PUBLISH_DIR:[ \t]+\\(.+\\)$") 212 | (:upload-dir "^#\\+UPLOAD_DIR:[ \t]+\\(.+\\)$") 213 | (:images-dir "^#\\+IMAGES_DIR:[ \t]+\\(.+\\)$") 214 | (:config-file "^#\\+CONFIG_FILE:[ \t]+\\(.+\\)$")) 215 | "Alist of options and matching regexps.") 216 | 217 | (defun blorg-version nil 218 | "Display blorg version." 219 | (interactive) 220 | (message "blorg version %s" blorg-version)) 221 | 222 | ;; FIXME: Is it the right place for it? 223 | (defadvice Footnote-add-footnote 224 | (before narrow-to-level) 225 | "Narrow to current level when adding a footnote in `org-mode'." 226 | (when (equal mode-name "Org") 227 | (org-narrow-to-subtree))) 228 | 229 | (defadvice Footnote-add-footnote 230 | (after widen) "Widen after editing a footnote in `org-mode'." 231 | (when (equal mode-name "Org") 232 | (widen))) 233 | 234 | (ad-activate 'Footnote-add-footnote) 235 | 236 | ;;; Customize groups 237 | 238 | (defgroup blorg nil 239 | "Export an `org-mode' buffer into a blog." 240 | :group 'org) 241 | 242 | ;; Put convert options for medium and small thumbnail 243 | ;; (defgroup blorg-images nil 244 | ;; "Handle images for `blorg'." 245 | ;; :group 'blorg) 246 | 247 | (defgroup blorg-templates-for-pages nil 248 | "HTML templates for `blorg'." 249 | :group 'blorg) 250 | 251 | (defgroup blorg-templates-for-posts nil 252 | "HTML templates for `blorg'." 253 | :group 'blorg) 254 | 255 | ;;; Customize variables 256 | 257 | ;; (defcustom blorg-use-registry nil 258 | ;; "Non-nil means blorg will keep a registry for each blog." 259 | ;; :type 'boolean 260 | ;; :group 'blorg) 261 | 262 | (defcustom blorg-config-file "" 263 | "Customization file for blorg." 264 | :type 'file 265 | :group 'blorg) 266 | 267 | (defcustom blorg-submit-post-string 268 | "Submit this post" 269 | "A string for the title of social bookmarking links." 270 | :type '(string) 271 | :group 'blorg) 272 | 273 | (defcustom blorg-strings 274 | `(:index-page-name "index" 275 | :page-extension ".html" 276 | :feed-extension ".xml" 277 | :meta-robots "index,follow" 278 | :read-more "Read more" 279 | :time-format "%A, %B %d %Y @ %R %z" 280 | :title-separator " - ") 281 | "A list of default strings." 282 | :type '(plist) 283 | :group 'blorg) 284 | 285 | (defcustom blorg-default-options 286 | `(:blog-title "[No_title]" 287 | :subtitle "[No_subtitle]" 288 | :author ,user-full-name 289 | :email ,user-mail-address 290 | :created ,(format-time-string (car org-time-stamp-formats)) 291 | :modified ,(format-time-string time-stamp-format) 292 | :blog-url "./" 293 | :homepage "[No_homepage]" 294 | :language ,(if (getenv "LANG") (substring (getenv "LANG") 0 2) "en") 295 | :encoding "UTF-8" 296 | :keywords "" 297 | :html-css "index.css" 298 | :xml-css "http://www.blogger.com/styles/atom.css" 299 | :feed-type "atom" 300 | ;; :seq-todo ,org-todo-keywords 301 | :done-string "DONE" 302 | :number-of-posts "12" 303 | :publish-dir "~/public_html/" 304 | :upload-dir "upload/" 305 | :images-dir "images/") 306 | "A list of default options. 307 | 308 | Changes in this list will apply globally to every `blorg' 309 | call. These options are overriden by their equivalent in the 310 | header of a file." 311 | :type '(plist) 312 | :group 'blorg) 313 | 314 | (defcustom blorg-post-number-per-page 315 | '((index . 10) (feed . 10) (tag . 10) (month . 10)) 316 | "Set how many posts you want to be displayed on each page." 317 | :type '(list (cons (const :tag "Index page" :value index) 318 | (integer :tag "Number")) 319 | (cons (const :tag "Feeds" :value feed) 320 | (integer :tag "Number")) 321 | (cons (const :tag "Tag page" :value tag) 322 | (integer :tag "Number")) 323 | (cons (const :tag "Month page" :value month) 324 | (integer :tag "Number"))) 325 | :group 'blorg) 326 | 327 | 328 | (defcustom blorg-publish-page-type '(feed tag month post) 329 | "Defines the blog structure. 330 | 331 | Allowed symbols are: feed tag month post. 332 | 333 | If `blorg-publish-page-type' is nil or '(feed), the blog consists 334 | in one single index page, without any tag or month page. In this 335 | case `blorg-publish' will ignore `blorg-put-full-post' and always 336 | put full posts in the index." 337 | :type '(repeat (symbol :tag "Page: ")) 338 | :group 'blorg) 339 | 340 | (defcustom blorg-reverse-posts-order nil 341 | "Non-nil means reverse order of posts publication." 342 | :type 'boolean 343 | :group 'blorg) 344 | 345 | (defcustom blorg-previous-posts-number 12 346 | "Number of previous posts to display." 347 | :type 'number 348 | :group 'blorg) 349 | 350 | (defcustom blorg-publish-feed '(index tag) 351 | "Publish feed for these pages. 352 | Allowed symbols are: index tag." 353 | :type '(repeat (symbol :tag "Feed for: ")) 354 | :group 'blorg) 355 | 356 | ;; (defcustom blorg-previous-posts-with-picture nil 357 | ;; "Insert small thumbnails within previous posts list." 358 | ;; :type 'boolean 359 | ;; :group 'blorg-images) 360 | 361 | (defcustom blorg-parg-in-headlines 1 362 | "Number of paragraphs in the short version of a post." 363 | :type 'number 364 | :group 'blorg) 365 | 366 | (defcustom blorg-tags-sort 'alphabetical 367 | "Sort tags by importance or by alphabetical order." 368 | :type '(radio (const :tag "Importance" importance) 369 | (const :tag "Alphabetical" alphabetical)) 370 | :group 'blorg) 371 | 372 | (defcustom blorg-rss-content-format 'txt 373 | "The format for rendering the content of RSS feeds." 374 | :group 'blorg 375 | :type '(radio (const :tag "Render in HTML" html) 376 | (const :tag "Leave as text" txt))) 377 | 378 | ;;; Templates 379 | 380 | (defcustom blorg-index-template 381 | " 382 | 383 |
384 | 385 | 388 | 389 |
390 |

(blorg-insert-author)

391 |
\n\n(blorg-insert-previous-posts)\n(blorg-insert-tags-as-cloud)\n(blorg-insert-archives)\n(blorg-insert-content)\n 392 |
393 | " 394 | "Template of the index page. 395 | 396 | Here is the list of defuns that you can insert in this template: 397 | 398 | (blorg-insert-index-url) : the URL of the index page 399 | (blorg-insert-homepage) : the URL of the author's homepage 400 | (blorg-insert-page-title) : the page title 401 | (blorg-insert-page-subtitle) : the page subtitle 402 | (blorg-insert-mailto-email) : mailto:your@email.com 403 | (blorg-insert-email) : your@email.com 404 | (blorg-insert-author) : author's name 405 | (blorg-insert-previous-posts) : a list of previous posts 406 | (blorg-insert-tags-as-cloud) : a cloud of tags 407 | (blorg-insert-tags-as-list) : a list of tags 408 | (blorg-insert-archives) : a list of months 409 | (blorg-insert-content) : the main content" 410 | :type 'string 411 | :group 'blorg-templates-for-pages) 412 | 413 | (defcustom blorg-tag-page-template 414 | " 415 | 416 |
417 | 418 | 421 | 422 |
423 |

(blorg-insert-author)

424 |
\n\n(blorg-insert-previous-posts)\n(blorg-insert-tags-as-cloud)\n(blorg-insert-archives)\n(blorg-insert-content)\n 425 |
426 | " 427 | "Template for the tag pages. 428 | 429 | Here is the list of defuns that you can insert in this template: 430 | 431 | (blorg-insert-index-url) : the URL of the index page 432 | (blorg-insert-homepage) : the URL of the author's homepage 433 | (blorg-insert-page-title) : the page title 434 | (blorg-insert-page-subtitle) : the page subtitle 435 | (blorg-insert-mailto-email) : mailto:your@email.com 436 | (blorg-insert-email) : your@email.com 437 | (blorg-insert-author) : author's name 438 | (blorg-insert-previous-posts) : a list of previous posts 439 | (blorg-insert-tags-as-cloud) : a list of tags 440 | (blorg-insert-tags-as-list) : a list of tags 441 | (blorg-insert-archives) : a list of months 442 | (blorg-insert-content) : the main content" 443 | :type 'string 444 | :group 'blorg-templates-for-pages) 445 | 446 | (defcustom blorg-month-page-template 447 | " 448 | 449 |
450 | 451 | 454 | 455 |
456 |

(blorg-insert-author)

457 |
\n\n(blorg-insert-tags-as-cloud)\n(blorg-insert-previous-posts)\n(blorg-insert-archives)\n(blorg-insert-content)\n 458 |
459 | " 460 | "Template for the month pages. 461 | 462 | Here is the list of defuns that you can insert in this template: 463 | 464 | (blorg-insert-index-url) : the URL of the index page 465 | (blorg-insert-homepage) : the URL of the author's homepage 466 | (blorg-insert-page-title) : the page title 467 | (blorg-insert-page-subtitle) : the page subtitle 468 | (blorg-insert-mailto-email) : mailto:your@email.com 469 | (blorg-insert-email) : your@email.com 470 | (blorg-insert-author) : author's name 471 | (blorg-insert-previous-posts) : a list of previous posts 472 | (blorg-insert-tags-as-cloud) : a cloud of tags 473 | (blorg-insert-tags-as-list) : a list of tags 474 | (blorg-insert-archives) : a list of months 475 | (blorg-insert-content) : the main content" 476 | :type 'string 477 | :group 'blorg-templates-for-pages) 478 | 479 | (defcustom blorg-post-page-template 480 | " 481 | 482 |
483 | 484 | 487 | 488 |
489 |

(blorg-insert-author)

490 |
\n\n(blorg-insert-content)\n 491 |
492 | " 493 | "Template for the post pages. 494 | 495 | Here is the list of defuns that you can insert in this template: 496 | 497 | (blorg-insert-index-url) : the URL of the index page 498 | (blorg-insert-homepage) : the URL of the author's homepage 499 | (blorg-insert-page-title) : the page title 500 | (blorg-insert-page-subtitle) : the page subtitle 501 | (blorg-insert-mailto-email) : mailto:your@email.com 502 | (blorg-insert-email) : your@email.com 503 | (blorg-insert-author) : author's name 504 | (blorg-insert-previous-posts) : a list of previous posts 505 | (blorg-insert-tags-as-cloud) : a cloud of tags 506 | (blorg-insert-tags-as-list) : a list of tags 507 | (blorg-insert-archives) : a list of months 508 | (blorg-insert-content) : the main content" 509 | :type 'string 510 | :group 'blorg-templates-for-pages) 511 | 512 | (defcustom blorg-post-template 513 | " 514 |
515 | 516 | 519 | 520 |
521 | (blorg-insert-post-author) 522 | (blorg-insert-post-dates) 523 | (blorg-insert-post-tags) 524 |
525 | 526 |
527 | (blorg-insert-post-content) 528 |
529 | 530 |
531 | " 532 | "Template for each post. 533 | 534 | Here is the list of defuns that you can insert in this template: 535 | 536 | (blorg-insert-post-url) : the URL of the post 537 | (blorg-insert-post-title) : the title of the post 538 | (blorg-insert-post-author) : the author of the post 539 | (blorg-insert-post-dates) : the publication and modification dates 540 | (blorg-insert-post-tags) : the tags for this post 541 | (blorg-insert-post-echos) : the \"Submit this post\" links 542 | (blorg-insert-post-content) : the main content of the post" 543 | :type 'string 544 | :group 'blorg-templates-for-posts) 545 | 546 | (defcustom blorg-post-author-template 547 | "

Author: (blorg-insert-author)

" 548 | "Template for the (blorg-insert-post-author) defun." 549 | :type 'string 550 | :group 'blorg-templates-for-posts) 551 | 552 | (defcustom blorg-post-dates-template 553 | "

(blorg-insert-post-publication-date)

" 554 | ;;

Updated: (blorg-insert-post-modification-date)

555 | "Template for the (blorg-insert-post-dates) defun." 556 | :type 'string 557 | :group 'blorg-templates-for-posts) 558 | 559 | (defcustom blorg-post-tags-template 560 | "

Tags: (blorg-insert-this-post-tags)

" 561 | ;;

Technorati: (blorg-insert-this-post-tags-to-technorati)

" 562 | "Template for the (blorg-insert-post-tags) defun." 563 | :type 'string 564 | :group 'blorg-templates-for-posts) 565 | 566 | 567 | (defcustom blorg-put-full-post 568 | '(index post) 569 | "Pages in which posts will appear as full posts. 570 | Posts in other pages are summarized. 571 | 572 | This list can include the following symbols: 573 | 574 | - index 575 | - feed 576 | - post 577 | - tag 578 | - month" 579 | :type '(repeat (symbol :tag "Page: ")) 580 | :group 'blorg-templates-for-posts) 581 | 582 | 583 | (defcustom blorg-put-author-in-post 584 | '(post tag) 585 | "Put author's name in posts when publishing these pages. 586 | See `blorg-put-full-post' for the list of available pages." 587 | :type '(repeat (symbol :tag "Page: ")) 588 | :group 'blorg-templates-for-posts) 589 | 590 | 591 | (defcustom blorg-put-echos-in-post 592 | '(post tag month) 593 | "Put \"echos\" in posts when publishing these pages. 594 | See `blorg-put-full-post' for the list of available pages." 595 | :type '(repeat (symbol :tag "Page: ")) 596 | :group 'blorg-templates-for-posts) 597 | 598 | 599 | (defcustom blorg-put-dates-in-post 600 | '(index post tag month) 601 | "Put dates in posts when publishing these pages. 602 | See `blorg-put-full-post' for the list of available pages." 603 | :type '(repeat (symbol :tag "Page: ")) 604 | :group 'blorg-templates-for-posts) 605 | 606 | 607 | (defcustom blorg-put-tags-in-post 608 | '(index post tag month) 609 | "Put tags in posts when publishing these pages. 610 | See `blorg-put-full-post' for the list of available pages." 611 | :type '(repeat (symbol :tag "Page: ")) 612 | :group 'blorg-templates-for-posts) 613 | 614 | ;;; make this an alist var with ("foramt string" post-url post-title) 615 | (defcustom blorg-echos-alist 616 | '(("\"Submit" post-abs-url blorgv-post-title post-tags blorg-submit-post-string blorg-submit-post-string) 617 | ("\"Submit" post-abs-url blorgv-post-title blorg-submit-post-string blorg-submit-post-string) 618 | ("\"Submit" post-abs-url blorgv-post-title post-tags blorg-submit-post-string blorg-submit-post-string) 619 | ("\"Submit" post-abs-url blorgv-post-title post-tags blorg-submit-post-string blorg-submit-post-string) 620 | ("\"Submit" post-abs-url blorgv-post-title post-tags blorg-submit-post-string blorg-submit-post-string) 621 | ("\"Submit" post-abs-url blorgv-post-title post-tags blorg-submit-post-string blorg-submit-post-string) 622 | ("\"Submit" post-abs-url blorgv-post-title post-tags blorg-submit-post-string blorg-submit-post-string) 623 | ("\"Submit" post-abs-url blorgv-post-title blorg-submit-post-string blorg-submit-post-string) 624 | ("\"Submit" post-abs-url blorgv-post-title post-tags blorg-submit-post-string blorg-submit-post-string) 625 | ("\"Submit" post-abs-url post-tags blorg-submit-post-string blorg-submit-post-string) 626 | ("\"Submit" post-abs-url blorgv-post-title post-tags blorg-submit-post-string blorg-submit-post-string)) 627 | "A alist of links to publish as \"echos\" of the post. 628 | Each cell in this list is a list of the form: 629 | 630 | \"[Formatting string] strings...\"" 631 | :type '(alist :key-type (string) 632 | :value-type (repeat symbol)) 633 | :group 'blorg-templates-for-posts) 634 | 635 | ;;; Main code 636 | (defvar blorg-set-header-done "" 637 | "Non-nil means header has been already parsed in this session.") 638 | 639 | (defun blorg-set-header (&optional force) 640 | "Set the header if it's not set and maybe FORCE the setting." 641 | (when (or (not (equal blorg-set-header-done (buffer-name))) force) 642 | (setq blorgv-header (blorg-parse-header) 643 | blorg-set-header-done (buffer-name)) 644 | (blorg-set-header-vars))) 645 | 646 | (defun blorg-set-header-vars nil 647 | "Set each var from the header." 648 | (setq blorgv-publish-index-only 649 | (not (and (memq 'tag blorg-publish-page-type) 650 | (memq 'month blorg-publish-page-type) 651 | (memq 'post blorg-publish-page-type))) 652 | blorgv-blog-url (plist-get blorgv-header :blog-url) 653 | blorgv-author (plist-get blorgv-header :author) 654 | blorgv-email (plist-get blorgv-header :email) 655 | blorgv-blog-title (plist-get blorgv-header :blog-title) 656 | blorgv-subtitle (plist-get blorgv-header :subtitle) 657 | blorgv-encoding (plist-get blorgv-header :encoding) 658 | blorgv-language (plist-get blorgv-header :language) 659 | blorgv-homepage (plist-get blorgv-header :homepage) 660 | blorgv-xml-css (plist-get blorgv-header :xml-css) 661 | blorgv-created-row (blorg-encode-time 662 | (or (plist-get blorgv-header :created) 663 | (format-time-string (car blorgv-time-stamp-formats))) 664 | "\\([0-9]+\\)-\\([0-9]+\\)-\\([0-9]+\\)") 665 | blorgv-created (blorg-timestamp-to-readable blorgv-created-row) 666 | blorgv-created-rfc822 (blorg-timestamp-to-rfc822 blorgv-created-row) 667 | blorgv-created-rfc3339 (blorg-timestamp-to-rfc3339 blorgv-created-row) 668 | blorgv-modified-row (blorg-encode-time 669 | (or (plist-get blorgv-header :modified) 670 | (format-time-string (car blorgv-time-stamp-formats))) 671 | "\\([0-9]+\\)-\\([0-9]+\\)-\\([0-9]+\\)") 672 | blorgv-modified (blorg-timestamp-to-readable blorgv-modified-row) 673 | blorgv-modified-rfc822 (blorg-timestamp-to-rfc822 blorgv-modified-row) 674 | blorgv-modified-rfc3339 (blorg-timestamp-to-rfc3339 blorgv-modified-row) 675 | blorgv-done-string (or (plist-get blorgv-header :done-string) "DONE") 676 | ;; (car (reverse (split-string (plist-get blorgv-header :seq-todo))))) 677 | blorgv-publish-d (plist-get blorgv-header :publish-dir) 678 | blorgv-upload-d (plist-get blorgv-header :upload-dir) 679 | blorgv-images-d (plist-get blorgv-header :images-dir) 680 | blorgv-keywords (plist-get blorgv-header :keywords) 681 | blorgv-feed-type (plist-get blorgv-header :feed-type))) 682 | 683 | (defun blorg-set-time-formats nil 684 | "Set time formats." 685 | (if org-display-custom-times 686 | (setq blorgv-time-stamp-formats org-time-stamp-custom-formats) 687 | (setq blorgv-time-stamp-formats org-time-stamp-formats))) 688 | 689 | 690 | ;;;###autoload 691 | (defun blorg-publish (&optional all) 692 | "Publish an `org-mode' file as a blog. 693 | If ALL is non-nil, force re-publication of each post." 694 | (interactive "P") 695 | (unless (eq major-mode 'org-mode) 696 | (error "Not in an org buffer")) 697 | (blorg-set-time-formats) 698 | (blorg-set-header all) 699 | (let* ((blorgv-content (blorg-parse-content 700 | blorgv-done-string 701 | blorg-reverse-posts-order all)) 702 | (tags (blorg-parse-tags)) 703 | (blorgv-tagstotal (blorg-count-tags-total tags)) 704 | (blorgv-tagsaverage (if tags (/ blorgv-tagstotal (length tags)) 1)) 705 | (new-tags (blorg-parse-new-tags blorgv-content)) 706 | (last-month 707 | (blorg-make-arch-month-list (format-time-string "%Y-%m-%d") 708 | blorgv-content)) 709 | (months-list 710 | (blorg-make-arch-month-list 711 | (progn (string-match ;;org-ts-regexp-both 712 | "[0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\}" 713 | (plist-get blorgv-header :created)) 714 | ;; (substring 715 | (match-string-no-properties 716 | 0 (plist-get blorgv-header :created))); 0 10)) 717 | blorgv-content))) 718 | (when (not blorgv-content) 719 | (error "No headline suitable for publication")) 720 | ;;; Load config file 721 | (unless (or (equal blorg-config-file "") 722 | (not (file-exists-p blorg-config-file))) 723 | (load-file blorg-config-file) 724 | (message "Blorg config file loaded")) 725 | (when (plist-get blorgv-header :config-file) 726 | (load-file (plist-get blorgv-header :config-file)) 727 | (message "Blorg local config file loaded")) 728 | ;; Maybe clean orphan files 729 | ;; (blorg-maybe-clean-orphan-files blorgv-content) 730 | (save-window-excursion 731 | (save-excursion 732 | ;; always publish index 733 | (blorg-render-index tags blorgv-content) 734 | (when (memq 'index blorg-publish-feed) 735 | (blorg-render-feed blorgv-content)) 736 | (when (memq 'tag blorg-publish-page-type) 737 | (blorg-render-tags-pages 738 | tags blorgv-content months-list 739 | (unless all new-tags) all)) 740 | (when (memq 'month blorg-publish-page-type) 741 | (blorg-render-month-pages 742 | tags blorgv-content (if all months-list last-month))) 743 | (when (memq 'month blorg-publish-page-type) 744 | (blorg-render-posts-html 745 | tags (blorg-limit-content-to-plist 746 | blorgv-content :post-force)))))) 747 | (when (get-buffer "*blorg feed output*") 748 | (kill-buffer "*blorg feed output*"))) 749 | 750 | (defun blorg-parse-new-tags (blorgv-content) 751 | "Parse BLORGV-CONTENT and look for new tags." 752 | (let (tags-list) 753 | (dolist (post blorgv-content) 754 | (mapcar (lambda (tag) (add-to-list 'tags-list tag)) 755 | (delete "" (split-string (plist-get post :post-tags) ":")))) 756 | (mapcar (lambda (tag) (cons tag 1)) tags-list))) 757 | 758 | ;;; Parsing 759 | (defun blorg-set-header-region nil 760 | "Return a cons defining the region of the blorgv-header." 761 | (save-excursion 762 | (goto-char (point-min)) 763 | (let (start end) 764 | (while (re-search-forward "^#\\+.+$" nil t) 765 | (if (match-string 0) 766 | (setq end (match-end 0)) 767 | (setq end (point-max)))) 768 | (cons (point-min) end)))) 769 | 770 | (defun blorg-parse-tags () 771 | "Make a sorted list of all tags from buffer. 772 | Each element of the list is a cons: (\"tag-name\" . number)." 773 | (let (alltags) 774 | (save-excursion 775 | (goto-char (point-min)) 776 | (while (and (re-search-forward ":\\([0-9A-Za-z@_]+\\):" nil t) 777 | (blorg-check-done)) 778 | (unless (assoc (match-string-no-properties 1) alltags) 779 | (let ((cnt 0)) 780 | (save-excursion 781 | (goto-char (point-min)) 782 | (while (and (re-search-forward 783 | (concat ":\\(" 784 | (regexp-quote 785 | (match-string-no-properties 1)) 786 | "\\):") nil t) 787 | (blorg-check-done)) 788 | (setq cnt (1+ cnt)))) 789 | (setq alltags 790 | (add-to-list 791 | 'alltags 792 | (cons (match-string-no-properties 1) 793 | cnt))))) 794 | (backward-char 1))) 795 | (blorg-sort-tags alltags blorg-tags-sort))) 796 | 797 | (defun blorg-parse-header nil 798 | "Create a plist containing blorgv-header options." 799 | (let* ((region (blorg-set-header-region)) 800 | (start (car region)) 801 | (end (cdr region)) 802 | (blorgv-header nil)) 803 | (dolist (opt blorg-options-regexps-alist) 804 | (add-to-list 'blorgv-header (car opt) t) 805 | (add-to-list 'blorgv-header (blorg-get-option 806 | start end opt) t)) blorgv-header)) 807 | 808 | (defun blorg-count-tags-total (taglist) 809 | "Count total number of tags in taglist." 810 | (let ((total 0)) 811 | (dolist (tag taglist) 812 | (setq total (+ total (cdr tag)))) total)) 813 | 814 | 815 | (defun blorg-get-option (start end option) 816 | "Look from START to END for OPTION and return it." 817 | (save-excursion 818 | (goto-char start) 819 | (cond ((and (re-search-forward (cadr option) end t) 820 | (match-string-no-properties 1)) 821 | (if (or ; Add blorgv-homepage ? 822 | (eq (car option) :blog-url) 823 | (eq (car option) :publish-dir) 824 | (eq (car option) :images-dir) 825 | (eq (car option) :upload-dir)) 826 | (file-name-as-directory 827 | (blorg-strip-trailing-spaces 828 | (match-string-no-properties 1))) 829 | (blorg-strip-trailing-spaces 830 | (match-string-no-properties 1)))) 831 | (t (plist-get blorg-default-options 832 | (car option)))))) 833 | 834 | 835 | (defun blorg-parse-content 836 | (blorgv-done-string reverse all) 837 | "Parse blorgv-content of an `org-mode' buffer. 838 | Check the presence of BLORGV-DONE-STRING in each post. 839 | REVERSE posts order is necessary. 840 | Maybe parse ALL posts." 841 | (let (posts (cnt 0)) 842 | (save-excursion 843 | (goto-char (point-min)) 844 | ;; match DONE and [#A] DONE as well 845 | (while (re-search-forward 846 | (concat "^\\* " blorgv-done-string 847 | " \\([^:\r\n]+\\)[ \t]*\\(:[A-Za-z@_0-9:]+\\)?[ \t]*$") 848 | nil t) 849 | (let* ((ttle (match-string-no-properties 1)) 850 | (tgs (or (match-string-no-properties 2) "")) 851 | (dte (blorg-encode-time 852 | (or (progn 853 | (save-excursion 854 | (re-search-forward 855 | org-ts-regexp-both 856 | (save-excursion 857 | (re-search-forward "^\\* " nil t)) t)) 858 | (match-string-no-properties 1)) 859 | (format-time-string (car blorgv-time-stamp-formats))) 860 | "\\([0-9]+\\)-\\([0-9]+\\)-\\([0-9]+\\)")) 861 | (post-exists 862 | (file-exists-p (concat blorgv-publish-d 863 | (blorg-make-post-url ttle))))) 864 | (add-to-list 'posts 865 | (blorg-parse-post 866 | cnt ttle tgs dte 867 | (if (save-excursion 868 | (re-search-forward "^\\* " nil t)) 869 | (match-beginning 0) 870 | (point-max)) 871 | post-exists all) t) 872 | (setq cnt (1+ cnt))))) 873 | (if reverse (reverse posts) posts))) 874 | 875 | 876 | (defun blorg-parse-post (number title tags dte end exists force) 877 | "Parse post NUMBER with TITLE and TAGS from DATE ending at END." 878 | `(:post-number ,number 879 | :post-title ,(blorg-strip-trailing-spaces title) 880 | :post-tags ,tags 881 | :post-exists ,exists 882 | :post-force ,(blorg-check-post-force force number exists) 883 | :post-closed ,dte 884 | :post-updated ,(current-time) 885 | :post-content ,(blorg-get-post-content end))) 886 | 887 | 888 | (defun blorg-check-post-force (force number exists) 889 | "Check whether post should be published depending on FORCE." 890 | (cond ((not exists) t) 891 | ((null force) nil) 892 | ((listp force) t) 893 | ((numberp force) (< number force)))) 894 | 895 | 896 | (defun blorg-get-post-content (end) 897 | "Get the blorgv-content of the post before END." 898 | (save-excursion 899 | (beginning-of-line) 900 | (while (or (looking-at (concat "[ \t]*" org-closed-string " ")) 901 | (looking-at (concat "[ \t]*" org-scheduled-string " ")) 902 | (looking-at "\\* ")) 903 | (forward-line 1)) 904 | (buffer-substring (point) end))) 905 | 906 | 907 | (defun blorg-check-done () 908 | "Check if the line begins with the DONE string. 909 | Also match \"* DONE [#A] ...\" and the likes." 910 | (save-excursion 911 | (save-match-data 912 | (beginning-of-line) 913 | (looking-at 914 | (concat 915 | "^\\*.+" 916 | (or (plist-get blorgv-header :done-string) "DONE")))))) 917 | ;; (car (reverse (split-string (plist-get blorgv-header :seq-todo)))))))))) 918 | 919 | 920 | (defun blorg-limit-content-to-number (lst num &optional rest) 921 | "Make a sublist of LST with the first NUM elements. 922 | If REST is non-nil, return the lst minus its first NUM elements." 923 | (if (< num (length lst)) 924 | (if rest (nthcdr num lst) 925 | (reverse (nthcdr (- (length lst) num) (reverse lst)))) 926 | (if (and rest (length lst)) nil lst))) 927 | 928 | 929 | (defun blorg-sort-tags (tags order) 930 | "Return a sorted alist of TAGS depending on ORDER. 931 | ORDER is either alphabetical-based or importance-based." 932 | (if (eq order 'alphabetical) 933 | (sort tags (lambda (fst scd) 934 | (string< (car fst) (car scd)))) 935 | (sort tags (lambda (fst scd) (> (cdr fst) (cdr scd)))))) 936 | 937 | 938 | ;;; Rendering 939 | (defun blorg-render-feed 940 | (blorgv-content &optional feed-name new-title) 941 | "Export a feed with BLORGV-HEADER and BLORGV-CONTENT. 942 | FEED-NAME might be either atom.xml/rss.xml or tag.xml. 943 | NEW-TITLE is needed to produce tag.xml depending on the tag itself." 944 | ;; First make sure everything is visible 945 | (widen) 946 | (show-all) 947 | (let* ((blorgv-feed-file-name 948 | (concat blorgv-publish-d 949 | (or feed-name 950 | (concat blorgv-feed-type 951 | (plist-get blorg-strings :feed-extension))))) 952 | (content (blorg-limit-content-to-number 953 | blorgv-content 954 | (cdr (assoc 'feed blorg-post-number-per-page))))) 955 | (with-temp-buffer 956 | (switch-to-buffer (get-buffer-create "*blorg feed output*")) 957 | (erase-buffer) 958 | (blorg-render-header-feed blorgv-feed-file-name new-title) 959 | (mapcar (lambda (new-post) 960 | (blorg-render-content-feed new-post)) 961 | content) 962 | (if (equal blorgv-feed-type "rss") 963 | (insert " \n") 964 | (insert "")) 965 | (write-file blorgv-feed-file-name) 966 | (kill-buffer (buffer-name))))) 967 | 968 | 969 | (defun blorg-render-header-feed 970 | (blorgv-feed-file-name &optional new-title) 971 | "Render the BLORGV-HEADER of buffer into atom blorgv-header. 972 | BLORGV-FEED-FILE-NAME is the feed filename. 973 | NEW-TITLE is the new title. Er." 974 | (let ((title (or new-title blorgv-blog-title))) 975 | (switch-to-buffer (get-buffer-create "*blorg feed output*")) 976 | (erase-buffer) 977 | (if (equal blorgv-feed-type "atom") 978 | (blorg-render-header-atom title) 979 | (blorg-render-header-rss title)))) 980 | 981 | 982 | (defun blorg-render-header-atom (title) 983 | "Render blorgv-header in atom format for TITLE." 984 | (insert " 985 | 986 | 987 | 988 | " title " 989 | " blorgv-subtitle " 990 | " blorgv-modified-rfc3339 " 991 | " blorgv-blog-url " 992 | 994 | 996 | Copyright (c) " (format-time-string "%Y") " " blorgv-author " 997 | 999 | " blorg-generated-by-string " 1000 | \n")) 1001 | 1002 | 1003 | (defun blorg-render-header-rss 1004 | (title) 1005 | "Render header in rss format for TITLE." 1006 | (insert " 1007 | 1008 | 1009 | " title " 1010 | " blorgv-blog-url " 1011 | " blorgv-language " 1012 | " blorgv-subtitle " 1013 | " blorgv-created-rfc822 " 1014 | " blorgv-modified-rfc822 " 1015 | (c)" (concat blorgv-author (format-time-string "%Y")) " 1016 | " blorgv-blog-url " 1017 | blorg version " blorg-version "\n")) 1018 | 1019 | 1020 | (defun blorg-render-content-feed (post) 1021 | "Render blorgv-content of feed with BLORGV-HEADER for POST." 1022 | (let* ((blorgv-post-title (plist-get post :post-title)) 1023 | (blorgv-published (if (equal blorgv-feed-type "atom") 1024 | (blorg-timestamp-to-rfc3339 1025 | (plist-get post :post-updated)) 1026 | (blorg-timestamp-to-rfc822 1027 | (plist-get post :post-updated)))) 1028 | (blorgv-updated (if (equal blorgv-feed-type "atom") 1029 | (blorg-timestamp-to-rfc3339 1030 | (plist-get post :post-closed)) 1031 | (blorg-timestamp-to-rfc822 1032 | (plist-get post :post-closed)))) 1033 | (blorgv-content (plist-get post :post-content)) 1034 | (blorgv-post-rel-url (blorg-make-post-url blorgv-post-title)) 1035 | (post-number (plist-get post :post-number))) 1036 | (switch-to-buffer (get-buffer-create "*blorg feed output*")) 1037 | (goto-char (point-max)) 1038 | (if (equal blorgv-feed-type "atom") 1039 | (blorg-render-content-atom) 1040 | (blorg-render-content-rss)))) 1041 | 1042 | 1043 | (defun blorg-render-content-rss nil 1044 | "Render content of feed in rss 2.0 format." 1045 | (insert " 1046 | 1047 | " blorgv-post-title " 1048 | " (concat blorgv-blog-url blorgv-post-rel-url) " 1049 | \n" (if (eq blorg-rss-content-format 'html) 1050 | (blorg-render-post-content-html blorgv-content) 1051 | (blorg-render-post-content-txt blorgv-content)) 1052 | " 1053 | " blorgv-modified-rfc822 " 1054 | " (concat blorgv-blog-url blorgv-post-rel-url) " 1055 | \n")) 1056 | 1057 | 1058 | (defun blorg-render-content-atom nil 1059 | "Render content of feed in atom format." 1060 | (insert " 1061 | 1062 | " blorgv-post-title " 1063 | 1065 | " (concat blorgv-blog-url blorgv-post-rel-url) " 1066 | " blorgv-updated " 1067 | " blorgv-published " 1068 | 1069 | " blorgv-author " 1070 | " blorgv-homepage " 1071 | " blorgv-email " 1072 | ") 1073 | (if (memq 'feed blorg-put-full-post) 1074 | (insert " 1075 | 1077 |
\n" 1078 | (blorg-render-post-content-html 1079 | blorgv-content t blorgv-post-rel-url) 1080 | "
1081 |
") 1082 | (insert " 1083 | 1085 |
\n" 1086 | (blorg-render-post-content-html 1087 | blorgv-content nil blorgv-post-rel-url) 1088 | "
1089 |
")) 1090 | (insert "\n
\n\n")) 1091 | 1092 | 1093 | (defun blorg-render-index 1094 | (tags blorgv-content) 1095 | "Render `org-mode' buffer. 1096 | BLORGV-HEADER TAGS BLORGV-CONTENT and MONTHS-LIST are required." 1097 | (with-temp-buffer 1098 | (switch-to-buffer (get-buffer-create "*blorg output*")) 1099 | (erase-buffer) 1100 | (blorg-render-header-html blorgv-header blorgv-blog-title 1101 | (if (equal blorgv-feed-type "atom") 1102 | "atom.xml" "rss.xml")) 1103 | (let* ((ctnt (blorg-limit-content-to-number 1104 | blorgv-content 1105 | (cdr (assoc 'index blorg-post-number-per-page)))) 1106 | (previous-posts (blorg-limit-content-to-number 1107 | blorgv-content 1108 | (cdr (assoc 'index blorg-post-number-per-page)) t)) 1109 | (ins-tags (memq 'index blorg-put-tags-in-post)) 1110 | (ins-auth (memq 'index blorg-put-author-in-post)) 1111 | (ins-echos (memq 'index blorg-put-echos-in-post)) 1112 | (ins-dates (memq 'index blorg-put-dates-in-post)) 1113 | (blorgv-ins-full 1114 | (or blorgv-publish-index-only 1115 | (memq 'index blorg-put-full-post)))) 1116 | (blorg-insert-body blorg-index-template) 1117 | (insert "\n") 1118 | (write-file (concat blorgv-publish-d 1119 | (plist-get blorg-strings :index-page-name) 1120 | (plist-get blorg-strings :page-extension))) 1121 | (kill-buffer (buffer-name))))) 1122 | 1123 | 1124 | (defun blorg-render-posts-html (tags blorgv-content) 1125 | "Render posts with TAGS and BLORGV-CONTENT." 1126 | (let* ((ins-tags (memq 'post blorg-put-tags-in-post)) 1127 | (ins-auth (memq 'post blorg-put-author-in-post)) 1128 | (ins-echos (memq 'post blorg-put-echos-in-post)) 1129 | (ins-dates (memq 'post blorg-put-dates-in-post)) 1130 | (blorgv-ins-full (memq 'post blorg-put-full-post)) 1131 | (post-keywords blorgv-keywords)) 1132 | (dolist (ctnt0 blorgv-content) 1133 | (let* ((ctnt (list ctnt0)) 1134 | (blorgv-post-title (plist-get ctnt0 :post-title)) 1135 | (blorgv-updated (blorg-timestamp-to-readable (plist-get ctnt0 :post-updated))) 1136 | (blorgv-published (blorg-timestamp-to-readable (plist-get ctnt0 :post-closed))) 1137 | (post-tags 1138 | (mapconcat 'eval (delete "" (split-string (plist-get ctnt0 :post-tags) ":")) " ")) 1139 | (post-file-name 1140 | (concat blorgv-publish-d (blorg-make-post-url blorgv-post-title)))) 1141 | (with-temp-buffer 1142 | (switch-to-buffer (get-buffer-create "*blorg output*")) 1143 | (erase-buffer) 1144 | (plist-put blorgv-header :tp-title 1145 | (concat blorgv-blog-title (plist-get blorg-strings :title-separator) 1146 | blorgv-post-title)) 1147 | (plist-put blorgv-header :tp-published blorgv-published) 1148 | (plist-put blorgv-header :tp-updated blorgv-updated) 1149 | (plist-put blorgv-header :tp-keywords (concat post-keywords " " post-tags)) 1150 | ;; Render blorgv-header 1151 | (blorg-render-header-html 1152 | blorgv-header (plist-get blorgv-header :tp-title)) 1153 | ;; Render body 1154 | (blorg-insert-body blorg-post-page-template) 1155 | (insert "\n") 1156 | (write-file post-file-name) 1157 | (kill-buffer (buffer-name))))))) 1158 | 1159 | 1160 | (defun blorg-render-tags-pages 1161 | (tags blorgv-content months-list new-tags all) 1162 | "Render one page per tag. 1163 | BLORGV-HEADER TAGS BLORGV-CONTENT MONTHS-LIST NEW-TAGS and ALL are required." 1164 | (dolist (tag (if all tags new-tags)) 1165 | (let* ((tag-name (car tag)) 1166 | (file-name (concat blorgv-publish-d tag-name 1167 | (plist-get blorg-strings :page-extension))) 1168 | (ins-tags (memq 'tag blorg-put-tags-in-post)) 1169 | (ins-auth (memq 'tag blorg-put-author-in-post)) 1170 | (ins-echos (memq 'tag blorg-put-echos-in-post)) 1171 | (ins-dates (memq 'tag blorg-put-dates-in-post)) 1172 | (blorgv-ins-full (memq 'tag blorg-put-full-post)) 1173 | (ctnt-tag (blorg-limit-content-to-tag blorgv-content tag-name)) 1174 | (tag-months-list (delq nil (blorg-check-arch-list 1175 | months-list ctnt-tag))) 1176 | (ctnt (blorg-limit-content-to-number 1177 | ctnt-tag 1178 | (cdr (assoc 'tag blorg-post-number-per-page)))) 1179 | (previous-posts (blorg-limit-content-to-number 1180 | ctnt-tag (cdr (assoc 'tag blorg-post-number-per-page)) t))) 1181 | (with-temp-buffer 1182 | (switch-to-buffer (get-buffer-create "*blorg output*")) 1183 | (erase-buffer) 1184 | (blorg-render-header-html 1185 | blorgv-header (concat blorgv-blog-title (plist-get blorg-strings 1186 | :title-separator) 1187 | tag-name) 1188 | (concat tag-name (plist-get blorg-strings :feed-extension)) tag) 1189 | (blorg-insert-body blorg-tag-page-template) 1190 | (insert "\n") 1191 | (write-file file-name) 1192 | (kill-buffer (buffer-name))) 1193 | (when (memq 'tag blorg-publish-feed) 1194 | (blorg-render-tag-feed 1195 | tag-name ctnt 1196 | (concat tag-name (plist-get blorg-strings :feed-extension))))))) 1197 | 1198 | 1199 | (defun blorg-render-month-pages (tags blorgv-content months-list) 1200 | "Render one page per month. 1201 | BLORGV-HEADER TAGS BLORGV-CONTENT and MONTHS-LIST are required." 1202 | (dolist (month months-list) 1203 | (let* ((month-name (car month)) 1204 | (file-name (concat blorgv-publish-d (cadr month))) 1205 | (ins-tags (memq 'month blorg-put-tags-in-post)) 1206 | (ins-auth (memq 'month blorg-put-author-in-post)) 1207 | (ins-echos (memq 'month blorg-put-echos-in-post)) 1208 | (ins-dates (memq 'month blorg-put-dates-in-post)) 1209 | (blorgv-ins-full (memq 'month blorg-put-full-post)) 1210 | (ctnt-month (blorg-limit-content-to-month blorgv-content month)) 1211 | (ctnt (blorg-limit-content-to-number 1212 | ctnt-month (cdr (assoc 'month blorg-post-number-per-page)))) 1213 | (previous-posts (blorg-limit-content-to-number 1214 | ctnt-month (cdr (assoc 'month blorg-post-number-per-page)) t))) 1215 | (with-temp-buffer 1216 | (switch-to-buffer (get-buffer-create "*blorg output*")) 1217 | (erase-buffer) 1218 | (blorg-render-header-html 1219 | blorgv-header (concat blorgv-blog-title 1220 | (plist-get blorg-strings :title-separator) 1221 | month-name)) 1222 | (blorg-insert-body blorg-month-page-template) 1223 | (insert "\n") 1224 | (write-file file-name) 1225 | (kill-buffer (buffer-name)))))) 1226 | 1227 | 1228 | (defun blorg-render-archives-list-html (months-list) 1229 | "Render MONTHS-LIST into an html list with CLASS." 1230 | (concat "
\n
    \n" 1231 | (mapconcat (lambda (mth) 1232 | (concat "
  • " 1233 | (car mth) "
  • ")) 1234 | months-list "\n") 1235 | "\n
\n
\n")) 1236 | 1237 | 1238 | (defun blorg-render-previous-posts-list (previous-posts) 1239 | "Render a list containing PREVIOUS-POSTS." 1240 | (with-temp-buffer 1241 | (when previous-posts 1242 | (insert "
\n
    \n")) 1243 | (mapc (lambda (post) 1244 | (insert "
  • " (plist-get post :post-title) 1248 | "
  • \n")) 1249 | (blorg-limit-content-to-number 1250 | previous-posts 1251 | blorg-previous-posts-number)) 1252 | (when previous-posts (insert "
\n
\n")) 1253 | (buffer-string))) 1254 | 1255 | 1256 | (defun blorg-render-tag-feed 1257 | (tag-name blorgv-content feed-name) 1258 | "Publish feed for tags. 1259 | TAG-NAME BLORGV-HEADER BLORGV-CONTENT and FEED-NAME are required." 1260 | (with-temp-buffer 1261 | (switch-to-buffer (get-buffer-create "*blorg feed output*")) 1262 | (erase-buffer) 1263 | (let ((new-con (blorg-sort-content-tag blorgv-content tag-name)) 1264 | (new-tit (concat blorgv-blog-title 1265 | (plist-get blorg-strings :title-separator) 1266 | tag-name))) 1267 | (blorg-render-feed 1268 | new-con feed-name new-tit)))) 1269 | 1270 | 1271 | (defun blorg-render-tags-list-html (tags) 1272 | "Render TAGS in a html list." 1273 | (with-temp-buffer 1274 | (insert "
\n
    \n") 1275 | (mapc (lambda (tag) 1276 | (insert "
  • [" (number-to-string (cdr tag)) 1277 | "] " 1280 | (car tag) 1281 | "
  • \n")) 1282 | tags) 1283 | (insert "
\n
\n\n") 1284 | (buffer-string))) 1285 | 1286 | 1287 | (defun blorg-calc-tag-size (level) 1288 | "Compute tag display size in percent depending on LEVEL." 1289 | (let ((base 100) 1290 | (step (/ 100 blorgv-tagstotal)) 1291 | (average blorgv-tagsaverage)) 1292 | (number-to-string (+ 100 (* step (- level average)))))) 1293 | 1294 | 1295 | (defun blorg-render-tags-cloud-html (tags) 1296 | "Render TAGS as a cloud in html." 1297 | (with-temp-buffer 1298 | (insert "
\n") 1299 | (mapc (lambda (tag) 1300 | (insert " " 1305 | (car tag) " ")) 1306 | tags) 1307 | (insert " \n
\n\n") 1308 | (buffer-string))) 1309 | 1310 | 1311 | (defun blorg-render-header-html 1312 | (blorgv-header page-title &optional feed-url tag) 1313 | "Render BLORGV-HEADER. 1314 | If PAGE-TITLE give a specific title to this page. 1315 | FEED-URL is the complete url for the feed page. 1316 | TAG is the set of tags." 1317 | (let ((keywords 1318 | (concat 1319 | (cond ((stringp (car tag)) 1320 | (concat (car tag) ", ")) 1321 | ((and (not (null (car tag))) 1322 | (listp (car tag))) 1323 | (concat (mapconcat 'car tag ", ") ", ")) 1324 | (t "")) 1325 | (mapconcat 1326 | 'eval 1327 | (split-string (or (plist-get blorgv-header :tp-keywords) 1328 | blorgv-keywords)) ", ") )) 1329 | (html-css (plist-get blorgv-header :html-css))) 1330 | (insert " 1332 | 1334 | 1335 | " page-title " 1336 | 1337 | 1338 | 1339 | 1340 | 1343 | 1344 | ") 1346 | (when feed-url (insert " 1347 | ")) 1350 | (insert "\n\n"))) 1351 | 1352 | 1353 | (defun blorg-render-content-html (post blorgv-blog-url) 1354 | "Render POST in html with BLORGV-BLOG-URL." 1355 | (let* ((blorgv-post-title (plist-get post :post-title)) 1356 | (blorgv-post-rel-url (blorg-make-post-url blorgv-post-title)) 1357 | (post-abs-url (concat blorgv-blog-url blorgv-post-rel-url)) 1358 | (tags (delete "" (split-string (plist-get post :post-tags) ":"))) 1359 | (post-tags (mapconcat (lambda (tag) tag) tags " ")) 1360 | (blorgv-tags-links (blorg-make-keywords-links tags)) 1361 | (technorati-tags-links 1362 | (blorg-make-keywords-links tags 'technorati)) 1363 | (blorgv-content (plist-get post :post-content))) 1364 | (plist-put blorgv-header :tp-published 1365 | (blorg-timestamp-to-readable (plist-get post :post-closed))) 1366 | (plist-put blorgv-header :tp-updated 1367 | (blorg-timestamp-to-readable (plist-get post :post-updated))) 1368 | (blorg-insert-post blorg-post-template))) 1369 | 1370 | 1371 | (defun blorg-make-post-url (blorgv-post-title) 1372 | "Make a permanent url from BLORGV-POST-TITLE." 1373 | (with-temp-buffer 1374 | (insert blorgv-post-title) 1375 | (goto-char (point-min)) 1376 | (while (< (point) (point-max)) 1377 | (cond ((member (char-after) '(233 232 224 244 239 249)) 1378 | (progn (delete-char 1))) 1379 | ((member (char-after) '(? ?\' ?/ ?% ?# ?= ?+)) 1380 | (progn (delete-char 1) (insert "-"))) 1381 | ((member (char-after) 1382 | '(?\" ?, ?\; ?: ?? ?! ?. ?$ ?\t)) 1383 | (progn (delete-char 1))) 1384 | ((not (eq (car (split-char (char-after))) 'ascii)) 1385 | (delete-char 1)) 1386 | (t (forward-char 1)))) 1387 | (concat (replace-regexp-in-string "-+$" "" (buffer-string)) 1388 | (plist-get blorg-strings :page-extension)))) 1389 | 1390 | 1391 | (defun blorg-limit-content-to-month (blorgv-content month) 1392 | "Limit BLORGV-CONTENT to posts of the MONTH." 1393 | (delq nil 1394 | (mapcar (lambda (post) 1395 | (when (and (plist-get post :post-closed) 1396 | (string-match 1397 | (caddr month) 1398 | (format-time-string 1399 | (car blorgv-time-stamp-formats) 1400 | (plist-get post :post-closed)))) 1401 | post)) blorgv-content))) 1402 | 1403 | 1404 | (defun blorg-limit-content-to-plist (blorgv-content plst) 1405 | "Limit BLORGV-CONTENT to posts with non-nil PLST." 1406 | (delq nil (mapcar (lambda (post) 1407 | (when (plist-get post plst) post)) 1408 | blorgv-content))) 1409 | 1410 | 1411 | (defun blorg-limit-content-to-tag (blorgv-content tag-name) 1412 | "Limit BLORGV-CONTENT to posts with TAG-NAME." 1413 | (delq nil 1414 | (mapcar (lambda (post) 1415 | (when (string-match 1416 | (regexp-quote tag-name) 1417 | (plist-get post :post-tags)) 1418 | post)) blorgv-content))) 1419 | 1420 | 1421 | (defun blorg-strip-trailing-spaces (string) 1422 | "Remove trailing whitespace in STRING." 1423 | (replace-regexp-in-string "[ \t]+$" "" string)) 1424 | 1425 | 1426 | (defun blorg-split-template (tpl) 1427 | "Split TPL into a list of functions." 1428 | (let* ((lst (split-string tpl "[\(\)]")) 1429 | (cnt 0)) 1430 | (dotimes (cnt (length lst)) 1431 | (when (fboundp (intern-soft (nth cnt lst))) 1432 | (setf (nth cnt lst) 1433 | (intern-soft (nth cnt lst))))) lst)) 1434 | 1435 | 1436 | (defun blorg-insert-body (tpl) 1437 | "Insert body of TPL." 1438 | (mapc (lambda (func) (eval func)) 1439 | (mapcar (lambda (part) 1440 | (if (stringp part) 1441 | (list 'insert part) 1442 | (macroexpand `(,part)))) 1443 | (blorg-split-template tpl)))) 1444 | 1445 | 1446 | (defun blorg-insert-post (tpl) 1447 | "Insert post with TPL." 1448 | (mapc (lambda (func) (eval func)) 1449 | (mapcar (lambda (part) 1450 | (if (stringp part) 1451 | (list 'insert part) 1452 | (macroexpand `(,part)))) 1453 | (blorg-split-template tpl)))) 1454 | 1455 | (defun blorg-sort-content-tag (blorgv-content tag-name) 1456 | "Remove posts from BLORGV-CONTENT if they don't match TAG-NAME." 1457 | (delq nil 1458 | (mapcar 1459 | '(lambda (post) 1460 | (when (string-match 1461 | (regexp-quote tag-name) 1462 | (plist-get post :post-tags)) 1463 | post)) 1464 | blorgv-content))) 1465 | 1466 | 1467 | (defun blorg-make-keywords-links (tags &optional site cloud) 1468 | "Convert TAGS into links with SITE." 1469 | (mapconcat 1470 | (lambda (tag) 1471 | (cond ((eq site 'technorati) 1472 | (concat "" tag "")) 1474 | (t (concat "" tag "")))) tags " ")) 1476 | 1477 | 1478 | ;;; Macros 1479 | (defmacro blorg-insert-index-url nil 1480 | "Insert index url." 1481 | `(insert (concat (plist-get blorg-strings :index-page-name) 1482 | (plist-get blorg-strings :page-extension)))) 1483 | 1484 | (defmacro blorg-insert-tag-name nil 1485 | "Insert tag-name." 1486 | `(insert tag-name)) 1487 | 1488 | (defmacro blorg-insert-month-name nil 1489 | "Insert month-name." 1490 | `(insert month-name)) 1491 | 1492 | (defmacro blorg-insert-email nil 1493 | "Insert blorgv-email." 1494 | `(insert blorgv-email)) 1495 | 1496 | (defmacro blorg-insert-mailto-email nil 1497 | "Insert mailto:email." 1498 | `(insert "mailto:" blorgv-email)) 1499 | 1500 | (defmacro blorg-insert-homepage nil 1501 | "Insert blorgv-homepage." 1502 | `(insert blorgv-homepage)) 1503 | 1504 | (defmacro blorg-insert-author nil 1505 | "Insert blorgv-author." 1506 | `(insert blorgv-author)) 1507 | 1508 | (defmacro blorg-insert-page-title nil 1509 | "Insert page-title." 1510 | `(insert ,(plist-get blorgv-header :blog-title))) 1511 | 1512 | (defmacro blorg-insert-page-subtitle nil 1513 | "Insert page-subtitle." 1514 | `(insert blorgv-subtitle)) 1515 | 1516 | (defmacro blorg-insert-content nil 1517 | "Insert main blorgv-content." 1518 | `(mapc 1519 | (lambda (new-post) 1520 | (blorg-render-content-html 1521 | new-post blorgv-blog-url)) 1522 | ctnt)) 1523 | 1524 | (defmacro blorg-insert-previous-posts nil 1525 | "Insert previous posts list." 1526 | `(when (not (or blorgv-publish-index-only 1527 | (null previous-posts))) 1528 | (insert (blorg-render-previous-posts-list 1529 | previous-posts)))) 1530 | 1531 | (defmacro blorg-insert-tags-as-list nil 1532 | "Insert tags list." 1533 | `(when (not (or blorgv-publish-index-only 1534 | (null tags))) 1535 | (insert (blorg-render-tags-list-html tags)))) 1536 | 1537 | (defmacro blorg-insert-tags-as-cloud nil 1538 | "Insert tags list." 1539 | `(when (not (or blorgv-publish-index-only 1540 | (null tags))) 1541 | (insert (blorg-render-tags-cloud-html tags)))) 1542 | 1543 | 1544 | (defmacro blorg-insert-archives nil 1545 | "Insert archive list." 1546 | `(when (not blorgv-publish-index-only) 1547 | (insert (blorg-render-archives-list-html 1548 | months-list)))) 1549 | 1550 | (defmacro blorg-insert-post-title nil 1551 | "Insert title of the post." 1552 | `(insert blorgv-post-title)) 1553 | 1554 | (defmacro blorg-insert-post-url nil 1555 | "Insert full url of the post." 1556 | `(insert blorgv-post-rel-url)) 1557 | 1558 | (defmacro blorg-insert-post-publication-date nil 1559 | "Insert publication date of the post." 1560 | `(insert (plist-get blorgv-header :tp-published))) 1561 | 1562 | (defmacro blorg-insert-post-modification-date nil 1563 | "Insert modification date of the post." 1564 | `(insert (plist-get blorgv-header :tp-updated))) 1565 | 1566 | (defmacro blorg-insert-this-post-tags nil 1567 | "Insert tags of the post." 1568 | `(insert blorgv-tags-links)) 1569 | 1570 | 1571 | ;; Don't put this as a default in templates 1572 | (defmacro blorg-insert-this-post-tags-to-technorati nil 1573 | "Insert technorati-tags links of the post." 1574 | `(insert technorati-tags-links)) 1575 | 1576 | 1577 | (defmacro blorg-insert-post-content nil 1578 | "Insert post blorgv-content." 1579 | (list 'insert `(blorg-render-post-content-html 1580 | blorgv-content ,(not (null blorgv-ins-full)) 1581 | blorgv-post-title))) 1582 | 1583 | 1584 | (defmacro blorg-insert-post-echos nil 1585 | "Insert \"echos\"links from `blorg-echos-alist'." 1586 | `(when (not (null ins-echos)) 1587 | (insert "
\n") 1588 | (dolist (elt blorg-echos-alist) 1589 | (insert " " (apply 'format elt) 1590 | "\n")) 1591 | (insert "
\n"))) 1592 | 1593 | 1594 | (defmacro blorg-insert-post-author nil 1595 | "Insert blorgv-author in post." 1596 | `(when (not (null ins-auth)) 1597 | (mapc (lambda (func) (eval func)) 1598 | (mapcar (lambda (part) 1599 | (if (stringp part) 1600 | (list 'insert part) 1601 | (macroexpand `(,part)))) 1602 | (blorg-split-template 1603 | blorg-post-author-template))))) 1604 | 1605 | 1606 | (defmacro blorg-insert-post-dates nil 1607 | "Insert dates in post." 1608 | `(when (not (null ins-dates)) 1609 | (mapc (lambda (func) (eval func)) 1610 | (mapcar (lambda (part) 1611 | (if (stringp part) 1612 | (list 'insert part) 1613 | (macroexpand `(,part)))) 1614 | (blorg-split-template 1615 | blorg-post-dates-template))))) 1616 | 1617 | 1618 | (defmacro blorg-insert-post-tags nil 1619 | "Insert tags in post." 1620 | `(when (and (not (null ins-tags)) 1621 | (not (equal ,blorgv-tags-links ""))) 1622 | (mapc (lambda (func) (eval func)) 1623 | (mapcar (lambda (part) 1624 | (if (stringp part) 1625 | (list 'insert part) 1626 | (macroexpand `(,part)))) 1627 | (blorg-split-template 1628 | blorg-post-tags-template))))) 1629 | 1630 | ;;; Exporting to HTML 1631 | (defun blorg-convert-parg nil 1632 | "Convert paragraphs." 1633 | (save-excursion 1634 | (goto-char (point-min)) 1635 | (while (re-search-forward "^[^ \n\r]+" nil t) 1636 | ;; Don't quote images/headings/quotes 1637 | (unless (save-match-data 1638 | (string-match "<[quod/lih]" (match-string 0))) 1639 | (goto-char (match-beginning 0)) 1640 | (insert "\n

\n") 1641 | (re-search-forward "^$" nil t) 1642 | (insert "

\n"))))) 1643 | 1644 | 1645 | (defun blorg-convert-ul nil 1646 | "Convert unordered list environments inside a post." 1647 | (save-excursion 1648 | (goto-char (point-min)) 1649 | (while (re-search-forward "^- " nil t) 1650 | (replace-match "
    \n
  • ") 1651 | (forward-line) 1652 | (let ((inside-list t)) 1653 | (while inside-list 1654 | (cond ((looking-at " [^ ]\\|\n") 1655 | (forward-line)) 1656 | ((looking-at "- ") 1657 | (replace-match "
  • \n
  • ") 1658 | (forward-line)) 1659 | (t (skip-chars-backward "\n") 1660 | (insert "
  • \n
") 1661 | (setq inside-list nil)))))))) 1662 | 1663 | 1664 | (defun blorg-convert-dl nil 1665 | "Convert description list environments inside a post." 1666 | (save-excursion 1667 | (goto-char (point-min)) 1668 | (while (re-search-forward "^- !\\(.+\\):" nil t) 1669 | (replace-match "
\n
\\1
") 1670 | (forward-line) 1671 | (let ((inside-list t)) 1672 | (while inside-list 1673 | (cond ((looking-at " [^ ]\\|\n") 1674 | (forward-line)) 1675 | ((looking-at "- !\\(.+\\):") 1676 | (replace-match "
\n
\\1
") 1677 | (forward-line)) 1678 | (t (skip-chars-backward "\n") 1679 | (insert "
\n
") 1680 | (setq inside-list nil)))))))) 1681 | 1682 | 1683 | (defun blorg-convert-ol nil 1684 | "Convert ordered list environments inside a post." 1685 | (save-excursion 1686 | (goto-char (point-min)) 1687 | (while (re-search-forward "^[0-9]+\\. " nil t) 1688 | (replace-match "
    \n
  1. ") 1689 | (forward-line) 1690 | (let ((inside-list t)) 1691 | (while inside-list 1692 | (cond ((looking-at " [^ ]\\|\n") 1693 | (forward-line)) 1694 | ((looking-at "^[0-9]+\\. ") 1695 | (replace-match "
  2. \n
  3. ") 1696 | (forward-line)) 1697 | (t (skip-chars-backward "\n") 1698 | (insert "
  4. \n
") 1699 | (setq inside-list nil)))))))) 1700 | 1701 | 1702 | (defun blorg-convert-fontification nil 1703 | "Convert fontified text in buffer." 1704 | (save-excursion 1705 | (goto-char (point-min)) 1706 | (open-line 1) 1707 | (while (next-single-property-change (point) 'face) 1708 | (goto-char (next-single-property-change (point) 'face)) 1709 | (let* ((table nil) 1710 | (prop (get-text-property (point) 'face))) 1711 | (cond 1712 | ;; convert subheadings 1713 | ((and (not (listp prop)) 1714 | (string-match "org-level-\\([0-9]\\)" (symbol-name prop))) 1715 | (let ((level (number-to-string 1716 | (1+ (string-to-number 1717 | (match-string 1 (symbol-name prop))))))) 1718 | (when (looking-at "\\*\\*+ \\(.+\\)$") 1719 | (replace-match (concat "" 1720 | (match-string-no-properties 1) 1721 | ""))))) 1722 | ;; convert fontification 1723 | ((and (not (null prop)) (listp prop)) 1724 | (blorg-convert-emphasis)) 1725 | ;; convert links 1726 | ((eq 'org-link prop) 1727 | (cond ((looking-at org-plain-link-re) 1728 | (blorg-convert-links (match-string 1) 1729 | (match-string 2))) 1730 | ((looking-at org-angle-link-re) 1731 | (blorg-convert-links (match-string 1) 1732 | (match-string 2))) 1733 | ((looking-at org-bracket-link-analytic-regexp) 1734 | (blorg-convert-links (match-string 2) 1735 | (match-string 3) 1736 | (match-string 5))))) 1737 | ;; convert tables and quotes 1738 | ((eq 'org-table prop) ; tables 1739 | (cond ((looking-at "\\+-+.+$") 1740 | (replace-match "")) 1741 | ((looking-at "|") 1742 | (let ((end-search 1743 | (save-excursion 1744 | (save-match-data 1745 | (if (re-search-forward "^[ \t]*[^|+]" nil t) 1746 | (match-beginning 0) 1747 | (point-max)))))) 1748 | (while (re-search-forward "^[ \t]*\\(|.+\\)$" end-search t) 1749 | (add-to-list 'table (match-string-no-properties 1) t) 1750 | (replace-match "")) 1751 | (insert (org-format-org-table-html table)))) 1752 | ;; fixed-with text 1753 | ((looking-at ":") 1754 | (insert "
\n")
1755 |                  (let ((end-search
1756 |                         (save-excursion
1757 |                           (save-match-data
1758 |                             (if (re-search-forward "^[^:]" nil t)
1759 |                                 (progn (goto-char (match-end 0))
1760 |                                        (skip-chars-backward "\n")
1761 |                                        (insert "\n
\n") 1762 | (match-beginning 0)) 1763 | (progn (goto-char (point-max)) 1764 | (skip-chars-backward "\n") 1765 | (insert "\n\n") 1766 | (point-max))))))) 1767 | (while (re-search-forward "^[ \t]*:\\(.+\\)$" end-search t) 1768 | (replace-match "\\1")))))) 1769 | ;; convert comments 1770 | ((or (eq 'font-lock-comment-face prop) 1771 | (eq 'org-formula prop) 1772 | (eq 'org-special-keyword prop)) 1773 | (kill-line) 1774 | (backward-char 1))))))) 1775 | 1776 | 1777 | (defun blorg-convert-emphasis nil 1778 | "Convert emphasis." 1779 | (save-excursion 1780 | (insert ? ) 1781 | (backward-char 1) 1782 | (cond ((looking-at org-emph-re) 1783 | (let ((body (match-string-no-properties 4)) 1784 | (postmatch (match-string-no-properties 5)) 1785 | (tag-b (nth 2 (assoc (match-string-no-properties 3) 1786 | org-emphasis-alist))) 1787 | (tag-e (nth 3 (assoc (match-string-no-properties 3) 1788 | org-emphasis-alist)))) 1789 | (replace-match (concat tag-b body tag-e postmatch) t)))))) 1790 | 1791 | (defconst blorg-special-html-chars 1792 | '(("&" . "&") 1793 | ("\"" . """) 1794 | ("<" . "<") 1795 | (">" . ">") 1796 | )) 1797 | 1798 | (defun blorg-escape-html-characters (text) 1799 | "Escape special XML/HTML characters -- <, >, &, etc." 1800 | (when text 1801 | (save-match-data 1802 | (mapcar (lambda (x) 1803 | (setf text (replace-regexp-in-string (car x) (cdr x) text))) 1804 | blorg-special-html-chars)) 1805 | text)) 1806 | 1807 | (defun blorg-convert-links 1808 | (url-type raw-link &optional link-desc) 1809 | "Convert URL-TYPE as a mix of RAW-LINK and LINK-DESC." 1810 | (let* ((raw-rel-link (file-name-nondirectory raw-link)) 1811 | (raw-link-ext (file-name-extension raw-link)) 1812 | (desc (or (blorg-escape-html-characters link-desc) raw-rel-link))) 1813 | (message "%s %s" url-type raw-link) 1814 | (cond 1815 | ;; files and images 1816 | ((equal url-type "file") 1817 | (if (save-match-data 1818 | (string-match (regexp-opt 1819 | image-file-name-extensions) 1820 | raw-link-ext)) 1821 | (replace-match (concat "\""")) 1823 | (replace-match (concat "" 1824 | desc "")))) 1825 | ((null url-type) 1826 | (replace-match (concat "" 1827 | desc ""))) 1828 | ;; other links 1829 | (t (replace-match (concat "" desc "")))))) 1832 | 1833 | (defun blorg-render-post-content-html 1834 | (blorgv-content full &optional blorgv-post-title) 1835 | "Render BLORGV-CONTENT of a post. 1836 | When FULL render full blorgv-content, otherwise just insert some headlines. 1837 | You can give a specific BLORGV-POST-TITLE to this post." 1838 | (with-temp-buffer 1839 | (insert blorgv-content) 1840 | (goto-char (point-min)) 1841 | (blorg-convert-fontification) 1842 | (blorg-convert-ol) 1843 | (blorg-convert-dl) 1844 | (blorg-convert-ul) 1845 | (blorg-convert-parg) 1846 | (delete-blank-lines) 1847 | (save-excursion 1848 | (goto-char (point-max)) 1849 | (delete-blank-lines)) 1850 | (if (null full) 1851 | (concat (buffer-substring 1852 | (point-min) 1853 | (progn (forward-paragraph 1854 | blorg-parg-in-headlines) 1855 | (point))) 1856 | (if (eq (match-end 0) (point-max)) "" 1857 | (concat "\n\" 1861 | (plist-get blorg-strings :read-more) 1862 | "\n"))) 1863 | (buffer-string)))) 1864 | 1865 | 1866 | (defun blorg-render-post-content-txt (blorgv-content) 1867 | "Render BLORGV-CONTENT of a post. 1868 | When FULL render full blorgv-content, otherwise just insert some headlines. 1869 | You can give a specific BLORGV-POST-TITLE to this post." 1870 | (with-temp-buffer 1871 | (insert blorgv-content) 1872 | (goto-char (point-min)) 1873 | (delete-blank-lines) 1874 | (save-excursion 1875 | (goto-char (point-max)) 1876 | (delete-blank-lines)) 1877 | (buffer-string))) 1878 | 1879 | 1880 | (defun blorg-make-arch-month-list 1881 | (blorgv-created blorgv-content) 1882 | "Depending on BLORGV-CREATED date, make a list from BLORGV-CONTENT containing each archived month." 1883 | (unless (not blorgv-content) 1884 | (let* ((start-y (string-to-number (car (split-string blorgv-created "-")))) 1885 | (start-m (string-to-number (cadr (split-string blorgv-created "-")))) 1886 | (end-y (nth 5 (decode-time))) 1887 | (end-m (nth 4 (decode-time))) 1888 | (nb-of-m (calendar-interval start-m start-y end-m end-y)) 1889 | arch-list) 1890 | (while (<= 0 nb-of-m) 1891 | (let ((month (mod end-m 12))) 1892 | (when (eq month 0) 1893 | (progn (setq end-y (1- end-y)) 1894 | (setq month 12))) 1895 | (add-to-list 1896 | 'arch-list 1897 | (list 1898 | ;; make labels for month-urls 1899 | (concat (calendar-month-name month) 1900 | " " (number-to-string end-y)) 1901 | ;; make urls for months 1902 | (concat (number-to-string end-y) 1903 | "_" (number-to-string month) 1904 | (plist-get blorg-strings :page-extension)) 1905 | ;; make "2006-05"-like string 1906 | (concat (number-to-string end-y) 1907 | "-" (if (< month 10) 1908 | (concat "0" (number-to-string month)) 1909 | (number-to-string month)))) t) 1910 | (setq end-m (1- end-m)) 1911 | (setq nb-of-m (1- nb-of-m)))) 1912 | (delq nil (blorg-check-arch-list arch-list blorgv-content))))) 1913 | 1914 | 1915 | (defun blorg-check-arch-list 1916 | (months-list blorgv-content) 1917 | "Check relevant entries in MONTHS-LIST depending on BLORGV-CONTENT." 1918 | (mapcar 1919 | (lambda (month) 1920 | (let ((month-str (nth 2 month))) 1921 | (when (memq 1922 | 't 1923 | (mapcar (lambda (post) 1924 | (not (null (string-match 1925 | month-str 1926 | (format-time-string 1927 | (car blorgv-time-stamp-formats) 1928 | (plist-get post :post-closed)))))) 1929 | blorgv-content)) 1930 | month))) 1931 | months-list)) 1932 | 1933 | ;;; Time functions 1934 | (defun blorg-timestamp-to-rfc3339 (time) 1935 | "Convert an `org-mode' TIMESTAMP to a RFC3339 time format. 1936 | Example: 1990-12-31T15:59:60-08:00" 1937 | (let* ((system-time-locale "C") 1938 | (zone1 (substring (format-time-string "%z" time nil) 0 3)) 1939 | (zone2 (substring (format-time-string "%z" time nil) 3))) 1940 | (concat (format-time-string "%Y-%m-%dT%H:%M:%S" time nil) 1941 | zone1 ":" zone2))) 1942 | 1943 | 1944 | (defun blorg-timestamp-to-rfc822 (time) 1945 | "Convert an `org-mode' TIMESTAMP to a RFC822 time format. 1946 | Example: Wed, 02 Oct 2002 15:00:00 +0200" 1947 | (let* ((system-time-locale "C")) 1948 | (concat (format-time-string "%a, %d %b %Y %H:%M:%S %z" time nil)))) 1949 | 1950 | 1951 | (defun blorg-timestamp-to-readable (time) 1952 | "Convert an `org-mode' TIMESTAMP to a readable format. 1953 | Example: Sunday, May 07 2006 @ 10:35 +0100" 1954 | (let ((system-time-locale "C")) 1955 | (format-time-string 1956 | (plist-get blorg-strings :time-format) time nil))) 1957 | 1958 | 1959 | (defun blorg-encode-time (timestamp format) 1960 | "Encode TIMESTAMP." 1961 | (when (string-match format timestamp) 1962 | (let ((year (string-to-number (match-string 1 timestamp))) 1963 | (month (string-to-number (match-string 2 timestamp))) 1964 | (day (string-to-number (match-string 3 timestamp))) 1965 | (hour (if (match-string 5 timestamp) 1966 | (string-to-number (match-string 5 timestamp)) 0)) 1967 | (min (if (match-string 6 timestamp) 1968 | (string-to-number (match-string 6 timestamp)) 0))) 1969 | (encode-time 0 min hour day month year)))) 1970 | 1971 | 1972 | 1973 | ;;;;########################################################################## 1974 | ;;;; User Options, Variables 1975 | ;;;;########################################################################## 1976 | 1977 | ;; Local Variables: *** 1978 | ;; mode:outline-minor *** 1979 | ;; End: *** 1980 | 1981 | ;;; blorg.el ends here 1982 | --------------------------------------------------------------------------------