neruda 0.1.3 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/bin/pablo +32 -18
- data/lib/neruda/config.rb +59 -16
- data/lib/neruda/config/lisp_config.rb +125 -79
- data/lib/neruda/config/org-config.el +5 -4
- data/lib/neruda/config/ox-neruda.el +28 -2
- data/lib/neruda/emacs.rb +44 -0
- data/lib/neruda/index.rb +44 -35
- data/lib/neruda/index/atom_generator.rb +16 -16
- data/lib/neruda/index/org_generator.rb +64 -41
- data/lib/neruda/org_file.rb +46 -13
- data/lib/neruda/org_file/class_methods.rb +36 -19
- data/lib/neruda/org_file/extracter.rb +12 -1
- data/lib/neruda/org_file/htmlizer.rb +5 -30
- data/lib/neruda/preview.rb +7 -5
- data/lib/neruda/templater.rb +3 -2
- data/lib/neruda/utils.rb +65 -31
- data/lib/neruda/version.rb +2 -1
- data/lib/tasks/org.rake +30 -15
- data/lib/tasks/site.rake +22 -12
- data/lib/tasks/tags.rake +2 -6
- data/locales/en.yml +20 -1
- data/locales/fr.yml +20 -1
- data/themes/default/css/htmlize.css +346 -0
- data/themes/default/css/style.css +115 -178
- data/themes/default/img/bottom.png +0 -0
- data/themes/default/img/tic.png +0 -0
- data/themes/default/img/top.png +0 -0
- metadata +32 -29
- data/themes/default/fonts/Yanone_Kaffeesatz_400.woff +0 -0
- data/themes/default/fonts/Yanone_Kaffeesatz_400.woff2 +0 -0
@@ -1,17 +1,18 @@
|
|
1
|
-
;; Add
|
1
|
+
;; Add org-mode to load path
|
2
2
|
(add-to-list 'load-path (expand-file-name "org-__ORG_VER__/lisp" "__WORK_DIR__"))
|
3
|
-
;; Load
|
3
|
+
;; Load last version of htmlize.el
|
4
4
|
(load-file (expand-file-name "htmlize.el" "__WORK_DIR__"))
|
5
5
|
|
6
6
|
;; Current project options
|
7
|
-
(setq neruda/
|
7
|
+
(setq neruda/version "__VERSION__"
|
8
|
+
neruda/current-work-dir "__WORK_DIR__"
|
8
9
|
user-mail-address "__AUTHOR_EMAIL__"
|
9
10
|
user-full-name "__AUTHOR_NAME__"
|
10
11
|
org-html-metadata-timestamp-format "__LONG_DATE_FMT__"
|
11
12
|
org-publish-project-alist
|
12
13
|
`(__ALL_PROJECTS__
|
13
14
|
__THEME_CONFIG__
|
14
|
-
("website" :components (__ALL_PROJECTS_NAMES__
|
15
|
+
("website" :components (__ALL_PROJECTS_NAMES__))))
|
15
16
|
|
16
17
|
;; Load neruda lib
|
17
18
|
(load-file (expand-file-name "ox-neruda.el" "__NERUDA_DIR__"))
|
@@ -33,13 +33,38 @@
|
|
33
33
|
|
34
34
|
;;; Function Declarations
|
35
35
|
|
36
|
+
(defvar neruda/version ""
|
37
|
+
"Version of the current neruda installation")
|
38
|
+
|
36
39
|
(defvar neruda/current-work-dir nil
|
37
40
|
"Location of the current neruda website base directory.")
|
38
41
|
|
39
42
|
(defvar neruda/org-temp-dir nil
|
40
|
-
"Location of the local
|
43
|
+
"Location of the local Org temporary directory (where to place
|
41
44
|
org timestamps and id locations).")
|
42
45
|
|
46
|
+
(defun neruda/org-html-format-spec (upstream info)
|
47
|
+
"Return format specification for preamble and postamble.
|
48
|
+
INFO is a plist used as a communication channel."
|
49
|
+
(let ((output (funcall upstream info)))
|
50
|
+
(push `(?A . ,(format "<span class=\"author\">%s</span>"
|
51
|
+
(org-export-data (plist-get info :author) info)))
|
52
|
+
output)
|
53
|
+
(push `(?k . ,(org-export-data (plist-get info :keywords) info)) output)
|
54
|
+
(push `(?K . ,(format "<ul class=\"keywords-list\">%s</ul>"
|
55
|
+
(mapconcat
|
56
|
+
(lambda (k) (format "<li class=\"keyword\">%s</li>" k))
|
57
|
+
(split-string (or (plist-get info :keywords) "") ",+ *")
|
58
|
+
"\n")))
|
59
|
+
output)
|
60
|
+
(push `(?l . ,(org-export-data (plist-get info :language) info)) output)
|
61
|
+
(push `(?n . ,(format "Neruda %s" neruda/version)) output)
|
62
|
+
(push `(?N . ,(format "<a href=\"https://git.umaneti.net/neruda/about/\">Neruda</a> %s" neruda/version)) output)
|
63
|
+
(push `(?x . ,(org-export-data (plist-get info :description) info)) output)
|
64
|
+
(push `(?X . ,(format "<p>%s</p>"
|
65
|
+
(org-export-data (plist-get info :description) info)))
|
66
|
+
output)))
|
67
|
+
|
43
68
|
(defun neruda/org-i18n-export (link description format)
|
44
69
|
"Export a i18n link"
|
45
70
|
(let* ((splitted-link (split-string link "|"))
|
@@ -72,6 +97,7 @@ org timestamps and id locations).")
|
|
72
97
|
make-backup-files nil
|
73
98
|
enable-local-variables :all
|
74
99
|
org-confirm-babel-evaluate nil
|
100
|
+
org-export-with-broken-links t
|
75
101
|
org-html-doctype "html5"
|
76
102
|
org-html-html5-fancy t
|
77
103
|
org-html-htmlize-output-type 'css
|
@@ -81,7 +107,7 @@ org timestamps and id locations).")
|
|
81
107
|
(strike-through . "<del>%s</del>")
|
82
108
|
(underline . "<span class=\"underline\">%s</span>")
|
83
109
|
(verbatim . "<code>%s</code>")))
|
84
|
-
|
110
|
+
(advice-add 'org-html-format-spec :around #'neruda/org-html-format-spec)
|
85
111
|
|
86
112
|
(provide 'ox-neruda)
|
87
113
|
|
data/lib/neruda/emacs.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'neruda/config'
|
4
|
+
|
5
|
+
module Neruda
|
6
|
+
# Wraps Gnu/Emacs calls
|
7
|
+
class Emacs
|
8
|
+
def initialize(file_path: nil, verbose: false)
|
9
|
+
@file = file_path
|
10
|
+
@verbose = verbose
|
11
|
+
end
|
12
|
+
|
13
|
+
def publish
|
14
|
+
if @file.nil?
|
15
|
+
emacs_args = ['--eval \'(org-publish "website")\'']
|
16
|
+
else
|
17
|
+
emacs_args = ['-f org-publish-current-file']
|
18
|
+
end
|
19
|
+
call_emacs emacs_args
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def emacs_command(arguments = [])
|
25
|
+
default_emacs = Neruda::Config.settings['emacs']
|
26
|
+
emacs_cmd = [default_emacs || 'emacs -Q --batch -nw']
|
27
|
+
emacs_cmd << '--eval \'(setq enable-dir-local-variables nil)\''
|
28
|
+
emacs_cmd << '--eval \'(setq inhibit-message t)\'' unless @verbose
|
29
|
+
emacs_cmd << '-l ./org-config.el'
|
30
|
+
emacs_cmd << "--eval '(find-file \"#{@file}\")'" unless @file.nil?
|
31
|
+
emacs_cmd.concat(arguments)
|
32
|
+
emacs_cmd.join(' ')
|
33
|
+
end
|
34
|
+
|
35
|
+
def call_emacs(arguments = [])
|
36
|
+
command = emacs_command arguments
|
37
|
+
if @verbose
|
38
|
+
warn command
|
39
|
+
return system(command, exception: true)
|
40
|
+
end
|
41
|
+
system command, out: '/dev/null', err: '/dev/null', exception: true
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/lib/neruda/index.rb
CHANGED
@@ -16,35 +16,32 @@ module Neruda
|
|
16
16
|
include Neruda::IndexAtomGenerator
|
17
17
|
include Neruda::IndexOrgGenerator
|
18
18
|
|
19
|
-
def initialize
|
20
|
-
@blog_path = Neruda::Config.settings['blog_path']
|
19
|
+
def initialize
|
21
20
|
@pubdir = Neruda::Config.settings['public_folder']
|
22
21
|
@index = { 'index' => [] }
|
22
|
+
@projects = {}
|
23
23
|
@tags_names = {}
|
24
24
|
@date = DateTime.now
|
25
|
-
|
26
|
-
|
27
|
-
else
|
28
|
-
@sources = sources_list(file_list)
|
29
|
-
filter_and_prefix_sources!
|
30
|
-
@sources.each { |f| add_to_indexes(Neruda::OrgFile.new(f)) }
|
31
|
-
sort!
|
32
|
-
end
|
25
|
+
feed
|
26
|
+
sort!
|
33
27
|
end
|
34
28
|
|
35
29
|
def entries
|
36
|
-
@index.keys
|
30
|
+
@index.keys.reject { |k| k == 'index' }
|
31
|
+
end
|
32
|
+
|
33
|
+
def empty?
|
34
|
+
@index['index'].empty?
|
37
35
|
end
|
38
36
|
|
39
|
-
def write_all(verbose
|
40
|
-
@index.
|
37
|
+
def write_all(verbose: true)
|
38
|
+
@index.each_key do |k|
|
41
39
|
write_org(k)
|
42
40
|
warn "Generated index file for #{k}" if verbose
|
43
41
|
write_atom(k)
|
44
42
|
warn "Generated atom feed for #{k}" if verbose
|
45
43
|
end
|
46
|
-
|
47
|
-
warn 'Generated all tags index' if verbose
|
44
|
+
write_all_blog_home(verbose)
|
48
45
|
end
|
49
46
|
|
50
47
|
def sort_by(kind)
|
@@ -61,35 +58,36 @@ module Neruda
|
|
61
58
|
|
62
59
|
private
|
63
60
|
|
64
|
-
def
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
def filter_and_prefix_sources!
|
71
|
-
exclude = Neruda::Config.settings['exclude_pattern']
|
72
|
-
sources = []
|
73
|
-
@sources.each do |f|
|
74
|
-
next if f == 'index.org'
|
75
|
-
if File.exist?(f)
|
76
|
-
file_path = f
|
61
|
+
def feed
|
62
|
+
Neruda::Config.sources.each do |project|
|
63
|
+
next unless project['is_blog']
|
64
|
+
if project['recursive']
|
65
|
+
file_pattern = '**/*.org'
|
77
66
|
else
|
78
|
-
|
79
|
-
|
67
|
+
file_pattern = '*.org'
|
68
|
+
end
|
69
|
+
Dir.glob(file_pattern, base: project['path']).map do |s|
|
70
|
+
org_file = File.join(project['path'], s)
|
71
|
+
add_to_indexes(
|
72
|
+
Neruda::OrgFile.new(org_file, project: project)
|
73
|
+
)
|
80
74
|
end
|
81
|
-
next if exclude && file_path.match(exclude)
|
82
|
-
sources << file_path
|
83
75
|
end
|
84
|
-
|
76
|
+
end
|
77
|
+
|
78
|
+
def add_to_project_index(article)
|
79
|
+
project = article.project
|
80
|
+
@projects[project['name']] ||= []
|
81
|
+
@projects[project['name']] << article
|
85
82
|
end
|
86
83
|
|
87
84
|
def add_to_indexes(article)
|
88
85
|
@index['index'] << article
|
86
|
+
add_to_project_index article
|
89
87
|
article.keywords.each do |k|
|
90
88
|
slug = Neruda::OrgFile.slug k
|
91
89
|
@tags_names[slug] = k # Overwrite is permitted
|
92
|
-
@index[slug]
|
90
|
+
@index[slug] ||= []
|
93
91
|
@index[slug] << article
|
94
92
|
end
|
95
93
|
end
|
@@ -98,16 +96,27 @@ module Neruda
|
|
98
96
|
@index.each do |k, i|
|
99
97
|
@index[k] = i.sort { |a, b| b.timekey <=> a.timekey }
|
100
98
|
end
|
99
|
+
@projects.each do |k, i|
|
100
|
+
@projects[k] = i.sort { |a, b| b.timekey <=> a.timekey }
|
101
|
+
end
|
101
102
|
end
|
102
103
|
|
103
104
|
def sort_tags_by_name_and_weight
|
104
105
|
tags_sorted = {}
|
105
|
-
all_keys =
|
106
|
+
all_keys = entries
|
106
107
|
tags_sorted[:by_name] = all_keys.sort
|
107
108
|
tags_sorted[:by_weight] = all_keys.sort do |a, b|
|
108
109
|
@index[b].length <=> @index[a].length
|
109
110
|
end
|
110
111
|
tags_sorted
|
111
112
|
end
|
113
|
+
|
114
|
+
def save?
|
115
|
+
return true unless empty?
|
116
|
+
Neruda::Config.sources.each do |project|
|
117
|
+
return true if project['is_blog'] && Dir.exist?(project['path'])
|
118
|
+
end
|
119
|
+
false
|
120
|
+
end
|
112
121
|
end
|
113
122
|
end
|
@@ -11,11 +11,11 @@ module Neruda
|
|
11
11
|
@index[index_name][0...10].each do |article|
|
12
12
|
content << atom_entry(article)
|
13
13
|
end
|
14
|
-
content.join("\n")
|
14
|
+
format '%<content>s</feed>', content: content.join("\n")
|
15
15
|
end
|
16
16
|
|
17
17
|
def write_atom(index_name)
|
18
|
-
return
|
18
|
+
return unless save?
|
19
19
|
slug = Neruda::OrgFile.slug index_name
|
20
20
|
FileUtils.mkdir_p "#{@pubdir}/feeds"
|
21
21
|
atomdest = "#{@pubdir}/feeds/#{slug}.xml"
|
@@ -31,17 +31,17 @@ module Neruda
|
|
31
31
|
def atom_header(title)
|
32
32
|
domain = Neruda::Config.settings['domain']
|
33
33
|
upddate = @date.rfc3339
|
34
|
-
slug = Neruda::OrgFile.slug(title)
|
35
|
-
tagurl = "#{domain}/tags/#{slug}.html"
|
36
34
|
if title == 'index'
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
35
|
+
slug = 'index'
|
36
|
+
tagurl = domain
|
37
|
+
title = Neruda::Config.settings['title'] || \
|
38
|
+
R18n.t.neruda.index.all_tags
|
39
|
+
else
|
40
|
+
slug = Neruda::OrgFile.slug(title)
|
41
|
+
tagurl = "#{domain}/tags/#{slug}.html"
|
42
42
|
title = @tags_names[title]
|
43
43
|
end
|
44
|
-
|
44
|
+
title = CGI.escapeHTML(title)
|
45
45
|
<<~ENDATOM
|
46
46
|
<?xml version="1.0" encoding="utf-8"?>
|
47
47
|
<feed xmlns="http://www.w3.org/2005/Atom"
|
@@ -49,13 +49,13 @@ module Neruda
|
|
49
49
|
xmlns:wfw="http://wellformedweb.org/CommentAPI/"
|
50
50
|
xml:lang="#{Neruda::Config.settings['lang']}">
|
51
51
|
|
52
|
-
<title>#{
|
52
|
+
<title>#{title}</title>
|
53
53
|
<link href="#{domain}/feeds/#{slug}.xml" rel="self" type="application/atom+xml"/>
|
54
|
-
<link href="#{tagurl}" rel="alternate" type="text/html" title="#{
|
54
|
+
<link href="#{tagurl}" rel="alternate" type="text/html" title="#{title}"/>
|
55
55
|
<updated>#{upddate}</updated>
|
56
56
|
<author><name>#{Neruda::Config.settings['author'] || ''}</name></author>
|
57
57
|
<id>urn:md5:#{Digest::MD5.hexdigest(domain)}</id>
|
58
|
-
<generator uri="https://
|
58
|
+
<generator uri="https://git.umaneti.net/neruda/about/">Neruda</generator>
|
59
59
|
ENDATOM
|
60
60
|
end
|
61
61
|
|
@@ -69,12 +69,12 @@ module Neruda
|
|
69
69
|
"<dc:subject>#{CGI.escapeHTML(k)}</dc:subject>"
|
70
70
|
end.join
|
71
71
|
keywords += "\n " if keywords != ''
|
72
|
-
|
72
|
+
title = CGI.escapeHTML(article.title)
|
73
73
|
<<~ENDENTRY
|
74
74
|
<entry>
|
75
|
-
<title>#{
|
75
|
+
<title>#{title}</title>
|
76
76
|
<link href="#{article.url}" rel="alternate" type="text/html"
|
77
|
-
title="#{
|
77
|
+
title="#{title}"/>
|
78
78
|
<id>urn:md5:#{Digest::MD5.hexdigest(article.timekey)}</id>
|
79
79
|
<published>#{article.datestring(:rfc3339)}</published>
|
80
80
|
<author><name>#{CGI.escapeHTML(article.author)}</name></author>
|
@@ -4,73 +4,96 @@ module Neruda
|
|
4
4
|
# Embeds methods responsible for generating an org file for a given
|
5
5
|
# index.
|
6
6
|
module IndexOrgGenerator
|
7
|
-
def to_org(index_name = 'index')
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
if year != last_year
|
13
|
-
content << ''
|
14
|
-
content << org_title(year)
|
15
|
-
last_year = year
|
16
|
-
end
|
17
|
-
content << org_entry(article)
|
18
|
-
end
|
19
|
-
content.join("\n")
|
7
|
+
def to_org(index_name = 'index', is_project: false)
|
8
|
+
return project_home_page(index_name) if is_project
|
9
|
+
return all_tags_index if index_name == 'index'
|
10
|
+
[org_header(index_name),
|
11
|
+
org_articles(@index[index_name])].join("\n")
|
20
12
|
end
|
21
13
|
alias_method :to_s, :to_org
|
22
14
|
|
23
15
|
def write_org(index_name)
|
24
|
-
return
|
25
|
-
|
26
|
-
|
27
|
-
|
16
|
+
return unless save?
|
17
|
+
slug = Neruda::OrgFile.slug index_name
|
18
|
+
FileUtils.mkdir 'tags' unless Dir.exist? 'tags'
|
19
|
+
content = to_org index_name
|
20
|
+
orgdest = "tags/#{slug}.org"
|
21
|
+
IO.write(orgdest, content)
|
28
22
|
end
|
29
23
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
content = [org_header(
|
24
|
+
private
|
25
|
+
|
26
|
+
def project_home_page(project_name)
|
27
|
+
content = [org_header(project_name, is_tag: false)]
|
28
|
+
if @projects[project_name]&.any?
|
29
|
+
content += org_articles(@projects[project_name])
|
30
|
+
end
|
31
|
+
content.join("\n")
|
32
|
+
end
|
33
|
+
|
34
|
+
def write_all_blog_home(verbose)
|
35
|
+
Neruda::Config.sources.each do |project|
|
36
|
+
next unless project['is_blog']
|
37
|
+
next unless Dir.exist?(project['path'])
|
38
|
+
warn "Generated blog home for #{project['name']}" if verbose
|
39
|
+
orgdest = format('%<root>s/index.org', root: project['path'])
|
40
|
+
IO.write(orgdest, to_org(project['name'], is_project: true))
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def all_tags_index
|
45
|
+
content = [
|
46
|
+
org_header(R18n.t.neruda.index.all_tags, is_tag: false)
|
47
|
+
]
|
34
48
|
sort_tags_by_name_and_weight.each do |t, tags|
|
35
49
|
content << ''
|
36
50
|
content << org_title(R18n.t.neruda.index.send(t), 'index-tags')
|
51
|
+
next if tags.empty?
|
37
52
|
tags.each do |k|
|
38
|
-
|
39
|
-
link = "[[#{domain}/tags/#{k}.html][#{title}]]"
|
40
|
-
content << "- #{link} (#{@index[k].length})"
|
53
|
+
content << "- #{tag_published_url(k)} (#{@index[k].length})"
|
41
54
|
end
|
42
55
|
end
|
43
|
-
|
44
|
-
src = 'src/tags/index.org'
|
45
|
-
IO.write(src, content.join("\n"))
|
56
|
+
content.join("\n")
|
46
57
|
end
|
47
58
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
src[1] = @blog_path if slug == 'index'
|
54
|
-
src.join('/')
|
59
|
+
def tag_published_url(tag_name)
|
60
|
+
domain = Neruda::Config.settings['domain']
|
61
|
+
title = @tags_names[tag_name]
|
62
|
+
tag_link = "#{domain}/tags/#{tag_name}.html"
|
63
|
+
"[[#{tag_link}][#{title}]]"
|
55
64
|
end
|
56
65
|
|
57
|
-
def org_header(title = nil)
|
58
|
-
if
|
59
|
-
title = Neruda::Config.settings['title']
|
60
|
-
elsif @tags_names.has_key?(title)
|
66
|
+
def org_header(title = nil, is_tag: true)
|
67
|
+
if is_tag
|
61
68
|
title = @tags_names[title]
|
69
|
+
elsif title.nil? || title == 'index'
|
70
|
+
title = Neruda::Config.settings['title']
|
62
71
|
end
|
63
|
-
<<~HEADER
|
72
|
+
head = <<~HEADER
|
64
73
|
#+title: #{title}
|
65
74
|
#+author: #{Neruda::Config.settings['author']}
|
66
75
|
#+language: #{Neruda::Config.settings['lang']}
|
67
76
|
HEADER
|
77
|
+
head.strip
|
78
|
+
end
|
79
|
+
|
80
|
+
def org_articles(articles_list)
|
81
|
+
last_year = nil
|
82
|
+
articles_list.map do |article|
|
83
|
+
year_title = ''
|
84
|
+
year = article.timekey.slice(0, 4)
|
85
|
+
if year != last_year
|
86
|
+
year_title = format("\n%<title>s\n", title: org_title(year))
|
87
|
+
last_year = year
|
88
|
+
end
|
89
|
+
year_title + org_entry(article)
|
90
|
+
end
|
68
91
|
end
|
69
92
|
|
70
93
|
def org_entry(article)
|
71
|
-
line = "- *[[
|
94
|
+
line = "- *[[#{article.url}][#{article.title}]]*"
|
72
95
|
if article.date
|
73
|
-
art_date = article.datestring(:full, false)
|
96
|
+
art_date = article.datestring(:full, year: false)
|
74
97
|
published = R18n.t.neruda.index.published_on art_date
|
75
98
|
line += " / #{published}"
|
76
99
|
end
|