Permalink
Browse files

Atom feeds with pretty diffs

  • Loading branch information...
1 parent cf32298 commit 41b80e001ad6a174fc78208fdb6dd76e614cd17e @vsedach committed Dec 3, 2011
Showing with 133 additions and 107 deletions.
  1. +0 −1 TODO
  2. +64 −17 src/diff.lisp
  3. +2 −2 src/dispatcher.lisp
  4. +4 −36 src/history.lisp
  5. +54 −46 src/recent-changes.lisp
  6. +5 −0 src/start.lisp
  7. +4 −5 static/css/style.css
View
1 TODO
@@ -1,3 +1,2 @@
-* Atom and not RSS!
* make sure code coloring is specified properly and works
* make sure email works
View
@@ -30,7 +30,8 @@
for modified-p = (typep reg 'diff:modified-diff-region)
for start = (funcall offset-fun reg)
for end = (+ start (funcall length-fun reg)) do
- (progn (when modified-p (princ "<span>" out))
+ (progn (when modified-p
+ (princ "<span style=\"color:red;\">" out))
(wrt str out start end)
(when modified-p (princ "</span>" out)))))))
(let ((rawdiff (diff:compute-raw-diff (str2arr original)
@@ -46,37 +47,83 @@
(defmethod diff:render-diff-window ((window wiki-diff-window) *html-stream*)
(labels ((escape (x) (when x (escape-for-html x)))
- (td (line dash class)
+ (td (line dash class style)
(if line
- #H[<td class="diff-marker">${dash}</td><td class="${class}">${line}</td>]
+ #H[<td class="diff-marker">${dash}</td>
+ <td class="${class}" style="${style}">${line}</td>]
#H[<td class="diff-marker" /><td />]))
(diff-line (original modified)
- (td original "-" "diff-deleteline")
- (td modified "+" "diff-addline")))
+ (td original "-" "diff-deleteline" "background-color: #FFA;")
+ (td modified "+" "diff-addline" "background-color: #CFC;")))
(loop for original in (choose-chunks (diff:window-chunks window) :delete :replace :create)
for modified in (choose-chunks (diff:window-chunks window) :create :insert :delete) do
(let ((original (escape original))
(modified (escape modified)))
#H[<tr>]
(if (and original modified)
(if (string= original modified)
- #H[<td class="diff-marker" />
- <td class="diff-context">${original}</td>
+ #H[<td class="diff-marker" style="height:4px;"/>
+ <td class="diff-context" style="background-color: #EEE;">${original}</td>
<td class="diff-marker" />
- <td class="diff-context">${original}</td>]
+ <td class="diff-context" style="background-color: #EEE;">${original}</td>]
(multiple-value-call #'diff-line
(compare-strings original modified)))
(diff-line original modified))
#H[</tr>]))))
+(defun path-or-blank (revision)
+ (if revision
+ (revision-path revision)
+ *blank-file*))
+
+(defun unified-diff-body (oldr newr)
+ (let ((diff (diff:format-diff-string 'diff:unified-diff
+ (path-or-blank oldr)
+ (revision-path newr))))
+ (subseq diff (nth-value 1 (ppcre:scan ".*\\n.*?\\n" diff)))))
+
(defun render-unified-revision-diff (oldr newr)
- #H[<br />--- ] (revision-version-info-links oldr)
+ #H[<div style="font-family:monospace;"><br />--- ]
+ (when oldr (revision-version-info-links oldr))
#H[<br />+++ ] (revision-version-info-links newr)
- #H[<br /><pre>]
- (let ((diff (diff:format-diff-string 'diff:unified-diff
- (revision-path oldr)
- (revision-path newr))))
- (princ (escape-for-html
- (subseq diff (nth-value 1 (ppcre:scan ".*\\n.*?\\n" diff))))
- *html-stream*))
- #H[</pre>])
+ #H[<br /><pre>${(escape-for-html (unified-diff-body oldr newr))}</pre></div>])
+
+(defun revision-version-info-links (r)
+ #H[Version ] (pprint-revision-link r) #H[ (${(link-to-edit r "edit")})])
+
+(defun render-diff-table (oldr diffr maybe-undo-button?)
+ #H[<div style="display:none;"><br />
+ Unified format diff:] (render-unified-revision-diff oldr diffr)
+ #H[Table format diff:
+ </div>
+ <table class="diff">
+ <colgroup>
+ <col class="diff-marker"> <col class="diff-content">
+ <col class="diff-marker"> <col class="diff-content">
+ </colgroup>
+ <tbody>
+ <tr>
+ <th colspan="2">] (when oldr (revision-version-info-links oldr)) #H[</th>
+ <th colspan="2">] (revision-version-info-links diffr)
+ (when (and maybe-undo-button?
+ (eq diffr (latest-revision (article diffr))))
+ (output-undo-link diffr))
+ #H[</th>
+ </tr>
+ ${(diff:format-diff-string 'wiki-diff
+ (path-or-blank oldr)
+ (revision-path diffr))}
+ </tbody>
+ </table>])
+
+(defpage /site/compare-revisions () (old diff)
+ (let* ((oldr (find-revision old))
+ (diffr (find-revision diff))
+ (title (title (article oldr))))
+ (when (> (date oldr) (date diffr))
+ (rotatef oldr diffr))
+ (setf *title* #?"${title} difference between revisions"
+ *footer* (with-output-to-string (*html-stream*)
+ (current-and-history-buttons oldr)))
+ #H[<div class="centered"><h1><a class="internal" href="${(link-to title)}">${title}</a></h1></div>]
+ (render-diff-table oldr diffr t)))
View
@@ -20,8 +20,8 @@
#H[Article was deleted.])
(defun render-article (article)
- (let ((*header* #?[<link rel="alternate" type="application/rss+xml" title="edits"
- href="$(#/site/article-feed/rss.xml?title={(title article)})">]))
+ (let ((*header* #?[<link rel="alternate" type="application/atom+xml" title="edits"
+ href="$(#/site/feed/article.atom?title={(title article)})">]))
(render-page (title article)
(if (typep article 'deleted-article)
(show-deleted-article-page article)
View
@@ -3,7 +3,9 @@
(defun output-undo-link (revision)
(unless (youre-banned?)
- #H[<form method="post" action="$(#/site/history-special)">(<input type= "hidden" name="r" value="${(store-object-id revision)}"/><input class="undo" type="submit" name="undo" value="undo" />)</form>]))
+ #H[<form method="post" action="$(#/site/history-special)">
+ <input type="hidden" name="r" value="${(store-object-id revision)}" />
+ (<input type="submit" name="undo" value="undo" class="undo" />)</form>]))
(defun output-compare-link (old new text)
#H[(<a class="internal" href="$(#/site/compare-revisions?old={(store-object-id old)}&diff={(store-object-id new)})">${text}</a>)])
@@ -40,40 +42,6 @@
(setf *footer* #?[<li><a href="${(link-to it)}">Current version</a></li>])))
-(defun revision-version-info-links (r)
- #H[Version ] (pprint-revision-link r) #H[ (${(link-to-edit r "edit")})])
-
-(defpage /site/compare-revisions () (old diff)
- (let* ((oldr (find-revision old))
- (diffr (find-revision diff))
- (title (title (article oldr))))
- (when (> (date oldr) (date diffr))
- (rotatef oldr diffr))
- (setf *title* #?"${title} difference between revisions"
- *footer* (with-output-to-string (*html-stream*)
- (current-and-history-buttons oldr)))
- #H[<div class="centered"><h1><a class="internal" href="${(link-to title)}">${title}</a></h1></div>
- <div class="hidden">
- Unified format diff:] (render-unified-revision-diff oldr diffr)
- #H[Table format diff:
- </div>
- <table class="diff">
- <colgroup>
- <col class="diff-marker"> <col class="diff-content">
- <col class="diff-marker"> <col class="diff-content">
- </colgroup>
- <tbody>
- <tr>
- <th colspan="2">] (revision-version-info-links oldr) #H[</th>
- <th colspan="2">] (revision-version-info-links diffr)
- (when (eq diffr (latest-revision (article diffr)))
- (output-undo-link diffr))
- #H[</th>
- </tr>
- ${(diff:format-diff-string 'wiki-diff (revision-path oldr) (revision-path diffr))}
- </tbody>
- </table>]))
-
;;; undo
(defun check-banned ()
@@ -104,4 +72,4 @@
(defhandler /site/history-special (old diff undo r)
(if undo
(undo r)
- #/site/compare-revisions?old={old}&diff={diff}))
+ #/site/compare-revisions?old={old}&diff={diff}))
View
@@ -4,10 +4,11 @@
(defvar *recent-revisions* ())
(defun init-recent-revisions ()
- (setf *recent-revisions*
- (sort (copy-list (store-objects-with-class 'revision))
- #'>
- :key #'date)))
+ (subseq (setf *recent-revisions*
+ (sort (copy-list (store-objects-with-class 'revision))
+ #'>
+ :key #'date))
+ 0 100))
(defun do-recent-revisions (f)
(loop for i from 0 below 100
@@ -18,61 +19,68 @@
(defun find-previous-revision (revision)
(cadr (member revision (revisions (article revision)))))
-(defun render-revision-summary (revision)
- #H[<li>] (pprint-revision-link revision)
+(defun %render-revision-summary (revision)
+ (pprint-revision-link revision)
#H[ <a class="internal" href="${(link-to (article revision))}">${(title (article revision))}</a>
- ${(summary revision)} ${(format-account-link (author revision))} ]
(awhen (find-previous-revision revision)
- (output-compare-link it revision "diff"))
- #H[</li>])
+ (output-compare-link it revision "diff")))
+
+(defun render-revision-summary (revision)
+ #H[<li>] (%render-revision-summary revision) #H[</li>])
(defpage /site/recent-changes "Recent Changes" ()
- (setf *header* #?[<link rel="alternate" type="application/rss+xml" title="recent changes" href="$(#/site/feed/rss.xml)">])
+ (setf *header* #?[<link rel="alternate" type="application/atom+xml" title="recent changes" href="$(#/site/feed/recent-changes.atom)">])
#H[<h1>Recent Changes</h1>
- <a class="internal" href="$(#/site/feed/rss.xml)">RSS feed</a>
+ <a class="internal" href="$(#/site/feed/recent-changes.atom)">ATOM feed</a>
<ul>] (do-recent-revisions #'render-revision-summary) #H[</ul>])
-;;; RSS feed
+;;; feed
-(defun rss-doc (title link description items-body)
- (setf (content-type*) "application/rss+xml")
+(defun iso8601-time (time)
+ (multiple-value-bind (second minute hour date month year)
+ (decode-universal-time time 0)
+ (format nil "~4,'0d-~2,'0d-~2,'0dT~2,'0d:~2,'0d:~2,'0dZ"
+ year month date hour minute second)))
+
+(defun feed-doc (title link updated entries-body)
+ (setf (content-type*) "application/atom+xml")
(with-output-to-string (*html-stream*)
#H[<?xml version="1.0" encoding="utf-8"?>
- <rss version="2.0">
- <channel>
- <title>${title}</title>
- <link>${link}</link>
- <description>${description}</description>]
- (funcall items-body)
- #H[</channel>
- </rss>]))
+ <feed xmlns="http://www.w3.org/2005/Atom">
+ <title>${title}</title>
+ <link href="${link}" />
+ <updated>${(iso8601-time updated)}</updated>]
+ (funcall entries-body)
+ #H[</feed>]))
+
+(defun feed-format-content (revision)
+ (escape-for-html
+ (with-output-to-string (*html-stream*)
+ (%render-revision-summary revision)
+ (render-diff-table (find-previous-revision revision) revision nil))))
-(defun rss-present-revision (revision)
- #H[<item>
- <title>${(name (author revision))}: ${(title (article revision))}</title>
- <link>${(link-to revision)}</link>
- <description>${(summary revision)}
-Diff:
-${(awhen (cadr (member revision (revisions (article revision))))
- (escape-for-html
- (diff:format-diff-string
- 'diff:unified-diff
- (revision-path it)
- (revision-path revision))))}
- </description>
- <pubDate>${(rfc-1123-date (date revision))}</pubDate>
- </item>])
+(defun feed-present-revision (revision)
+ #H[<entry>
+ <title>${(title (article revision))} - ${(summary revision)} ${(name (author revision))}</title>
+ <link href="${(link-to revision)}" type="text/html" />
+ <updated>${(iso8601-time (date revision))}</updated>
+ <content type="html">${(feed-format-content revision)}</content>
+</entry>])
-(%defpage /site/feed/rss.xml :get ()
- (rss-doc
- "CLiki Recent Changes" #/site/feed/rss.xml "CLiki Recent Changes"
+(%defpage /site/feed/recent-changes.atom :get ()
+ (feed-doc
+ "CLiki Recent Changes" #/site/feed/recent-changes.atom
+ (date (car *recent-revisions*))
(lambda ()
- (do-recent-revisions #'rss-present-revision))))
+ (do-recent-revisions #'feed-present-revision))))
-(%defpage /site/article-feed/rss.xml :get (title)
+(%defpage /site/feed/article.atom :get (title)
(awhen (find-article-any title)
- (let ((description #?"CLiki Article ${title} Edits"))
- (rss-doc
- description #/site/article-feed/rss.xml?title={title} description
- (lambda ()
- (map nil #'rss-present-revision (revisions it)))))))
+ (feed-doc
+ #?"CLiki Article ${title} Edits"
+ #/site/feed/article.atom?title={title}
+ (date (latest-revision it))
+ (lambda ()
+ (loop repeat 20 for revision in (revisions it)
+ do (feed-present-revision revision))))))
View
@@ -20,6 +20,11 @@
(defmethod bknr.datastore::ensure-store-random-state :around ((store store))
(bknr.datastore::initialize-store-random-state store))
+(defvar *blank-file*
+ (let ((pathname #P"/tmp/cliki2blankfile"))
+ (close (open pathname :if-does-not-exist :create))
+ pathname))
+
(defvar %snapshot-thread
(bt:make-thread
(lambda ()
View
@@ -263,12 +263,11 @@ pre, pre *, .code, .code * { font-family: monospace; }
table.diff { border: none; border-spacing: 3px; table-layout: fixed; width:100%; }
table.diff a { text-decoration: none; }
table.diff col.diff-content { width: 48%; }
-td.diff-marker {font-size: smaller; text-align: right; height:20px;}
+td.diff-marker {font-size: smaller; text-align: right;}
td.diff-line-number { font-weight: bold; }
-td.diff-context { font-size: smaller; background-color: #EEE;}
-td.diff-deleteline { font-size: smaller; background-color: #FFA;}
-td.diff-addline { font-size: smaller; background-color: #CFC;}
-table.diff span { color: red; }
+td.diff-context { font-size: smaller;}
+td.diff-deleteline { font-size: smaller;}
+td.diff-addline { font-size: smaller;}
.regin {
border:1px solid #a4a4a4;

0 comments on commit 41b80e0

Please sign in to comment.