fronde 0.6.1 → 0.6.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fa9e00cb764be5f63bca69b6d11b338955a38c9c371b848e4bbe15b5f9c27a3e
4
- data.tar.gz: ca6b276ee9fa2df53886ee26452ae3a3f80ac892d4e47ee67afdc4e7d6f0a54f
3
+ metadata.gz: 4f351a91fd7e7e674a9e7b3120725960cd36cc02a4c7d6d39715f760f4527b75
4
+ data.tar.gz: 4b371b41a1658aed730c2cb533bc8f68178d3a0d1ae791fb598aa7ab9eda5372
5
5
  SHA512:
6
- metadata.gz: 657a9f2db5b42239358e92594377f3c2da9c0b2ae2aca2218e04108a462617fdb94e4ca4c71b43c4d236863126383471d699caae0d611c49196064d25c3439a8
7
- data.tar.gz: 9a6db63382ac26264e1e6661d942693958137f0502fdc0616a2e7b6c86cace6a461d8dbb13b91fb219a973e7f021b21e9f35198df621299c7eff8424371f72fa
6
+ metadata.gz: bb1c612a0e6139a16ef798847579018494a171965e05b4535621906c4c488f62796fbbaa234b2b6566596335c47b9bce49d32d47eda772941ae8829e3ee2443f
7
+ data.tar.gz: 10b549865a13777b2e37e8beff967603b030d51bb7e3d7ea1bd664e2883d4b9c5c13271c1c6c718d8d6f6b8e70064ed5e032e81e7a84aecb70d3fc95e7480685
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'shellwords'
3
4
  require_relative 'helpers'
4
5
  require_relative 'opt_parse'
5
6
  require_relative '../slug'
@@ -47,8 +48,7 @@ module Fronde
47
48
  end
48
49
 
49
50
  def fronde_open
50
- editor = ENV['EDITOR'] || ENV['VISUAL'] || 'emacs'
51
- cmd = [editor]
51
+ cmd = (ENV['EDITOR'] || ENV['VISUAL'] || 'emacs').shellsplit
52
52
  file_path = @argv.first || Dir.pwd
53
53
  unless File.file?(file_path)
54
54
  # file_path may be updated with title given in options
@@ -58,7 +58,7 @@ module Fronde
58
58
  cmd << '+6'
59
59
  end
60
60
  cmd << file_path
61
- system(*cmd)
61
+ system(*cmd, exception: true)
62
62
  end
63
63
 
64
64
  def fronde_publish
@@ -21,5 +21,5 @@
21
21
  ("website" :components ("{{ all_projects | map: 'name' | join: '" "' | remove: '" "tags' }}"))))
22
22
 
23
23
  ;; Load fronde lib
24
- (load-file (expand-file-name "ox-gmi.el" "{{ work_dir }}/lib"))
24
+ (load-file (expand-file-name "ox-gmi.el" "{{ fronde_data_dir }}"))
25
25
  (load-file (expand-file-name "ox-fronde.el" "{{ fronde_data_dir }}"))
@@ -97,7 +97,7 @@ INFO is a plist used as a communication channel."
97
97
  output)
98
98
  (push `(?l . ,(org-export-data (plist-get info :language) info)) output)
99
99
  (push `(?n . ,(format "Fronde %s" fronde-version)) output)
100
- (push `(?N . ,(format "<a href=\"https://etienne.depar.is/fronde/\">Fronde</a> %s" fronde-version)) output)
100
+ (push `(?N . ,(format "<a href=\"https://etienne.pflieger.bzh/fronde/\">Fronde</a> %s" fronde-version)) output)
101
101
  (push `(?x . ,(org-export-data (plist-get info :description) info)) output)
102
102
  (push `(?X . ,(format "<p>%s</p>"
103
103
  (org-export-data (plist-get info :description) info)))
@@ -0,0 +1,654 @@
1
+ ;;; ox-gmi.el --- Gemini Back-End for Org Export Engine -*- lexical-binding: t; -*-
2
+
3
+ ;; Copyright (C) 2020 Étienne Pflieger
4
+
5
+ ;; Author: Étienne Pflieger <etienne@pflieger.bzh>
6
+ ;; Created: 29 November 2020
7
+ ;; Version: 0.2
8
+ ;; Package-Requires: ((emacs "27.1"))
9
+ ;; Keywords: wp
10
+ ;; Homepage: https://git.umaneti.net/ox-gmi.el/
11
+
12
+ ;;; License:
13
+
14
+ ;; This file is not part of GNU Emacs.
15
+ ;; However, it is distributed under the same license.
16
+
17
+ ;; GNU Emacs is free software; you can redistribute it and/or modify
18
+ ;; it under the terms of the GNU General Public License as published by
19
+ ;; the Free Software Foundation; either version 3, or (at your option)
20
+ ;; any later version.
21
+
22
+ ;; GNU Emacs is distributed in the hope that it will be useful,
23
+ ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
24
+ ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25
+ ;; GNU General Public License for more details.
26
+
27
+ ;; You should have received a copy of the GNU General Public License
28
+ ;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
29
+
30
+ ;;; Commentary:
31
+
32
+ ;; This library implements a Gemini back-end for Org exporter, based on
33
+ ;; `markdown' back-end. It also heavily depends on the `ascii' back-end.
34
+
35
+ ;;; Installation:
36
+
37
+ ;; Obviously, this package depends on `org-mode', which must be loaded first.
38
+
39
+ ;; You first need to download this file. We recommend you to put it
40
+ ;; somewhere under your `user-emacs-directory' folder (often ~/.emacs.d).
41
+
42
+ ;; cd ~/.emacs.d
43
+ ;; curl -O https://git.umaneti.net/fronde/plain/lib/fronde/config/data/ox-gmi.el
44
+
45
+ ;; Then, you may want to compile it. You can do so with the Emacs command
46
+ ;; M-x byte-compile-file RET ~/.emacs.d/ox-gmi.el
47
+
48
+ ;; When it's done, you can add the following line in your GNU Emacs config
49
+ ;; file:
50
+ ;; (load-file "~/.emacs.d/ox-gmi.elc")
51
+
52
+ ;; And everything should be fine.
53
+
54
+
55
+ ;;; Code:
56
+
57
+ (require 'ox-ascii)
58
+ (require 'ox-publish)
59
+
60
+ (declare-function gemini-mode "gemini")
61
+
62
+
63
+ ;;; Define Back-End
64
+
65
+ (org-export-define-derived-backend 'gmi 'ascii
66
+ :menu-entry
67
+ '(?g "Export to Gemini"
68
+ ((?G "To temporary buffer"
69
+ (lambda (a s v b) (org-gmi-export-as-gemini a s v)))
70
+ (?g "To file"
71
+ (lambda (a s v b) (org-gmi-export-to-gemini a s v)))
72
+ (?o "To file and open"
73
+ (lambda (a s v b)
74
+ (if a (org-gmi-export-to-gemini t s v)
75
+ (org-open-file (org-gmi-export-to-gemini nil s v)))))))
76
+ :translate-alist '((center-block . org-gmi-center)
77
+ (example-block . org-gmi-preformatted-block)
78
+ (export-block . org-gmi-export-block)
79
+ (fixed-width . org-gmi-preformatted-block)
80
+ (footnote-reference . org-gmi-footnote-reference)
81
+ (headline . org-gmi-headline)
82
+ (inner-template . org-gmi-inner-template)
83
+ (item . org-gmi-item)
84
+ (keyword . org-gmi-keyword)
85
+ (line-break . org-gmi-line-break)
86
+ (link . org-gmi-link)
87
+ (paragraph . org-gmi-paragraph)
88
+ (quote-block . org-gmi-quote-block)
89
+ (section . org-gmi-section)
90
+ (src-block . org-gmi-preformatted-block)
91
+ (template . org-gmi-template))
92
+ :options-alist '((:creator "CREATOR" nil org-gmi-creator-string)
93
+ (:description "DESCRIPTION" nil nil parse)
94
+ (:keywords "KEYWORDS" nil nil parse)
95
+ (:subtitle "SUBTITLE" nil nil parse)
96
+ (:gemini-postamble
97
+ nil "gemini-postamble" org-gmi-postamble)
98
+ (:gemini-timestamp-format
99
+ nil nil org-gmi-timestamp-format)
100
+ (:gemini-postamble-format
101
+ nil nil org-gmi-postamble-format)))
102
+
103
+
104
+
105
+ ;;; Inner Variables
106
+
107
+ (defvar org-gmi--links-in-section '()
108
+ "AList storing all links in current section.")
109
+
110
+
111
+
112
+ ;;; User Configuration Variables
113
+
114
+ (defgroup org-export-gmi nil
115
+ "Options for exporting Org mode files to Gemini."
116
+ :tag "Org Export Gemini"
117
+ :group 'org-export)
118
+
119
+ (defcustom org-gmi-postamble 't
120
+ "Non-nil means insert a postamble in Gemini export.
121
+
122
+ When set to `auto', check against the
123
+ `org-export-with-author/email/creator/date' variables to set the
124
+ content of the postamble. When set to a string, use this string
125
+ as the postamble. When t, insert a string as defined by the
126
+ formatting string in `org-gmi-postamble-format'.
127
+
128
+ When set to a function, apply this function and insert the
129
+ returned string. The function takes the property list of export
130
+ options as its only argument.
131
+
132
+ Setting :gemini-postamble in publishing projects will take
133
+ precedence over this variable."
134
+ :group 'org-export-gmi
135
+ :type '(choice (const :tag "No postamble" nil)
136
+ (const :tag "Auto postamble" auto)
137
+ (const :tag "Default formatting string" t)
138
+ (string :tag "Custom formatting string")
139
+ (function :tag "Function (must return a string)")))
140
+
141
+ (defcustom org-gmi-postamble-format
142
+ '(("en" "📝 %a with %c\n📅 %d")
143
+ ("fr" "📝 %a avec %c\n📅 %d"))
144
+ "Alist of languages and format strings for the Gemini postamble.
145
+
146
+ The first element of each list is the language code, as used for
147
+ the LANGUAGE keyword. See `org-export-default-language'.
148
+
149
+ The second element of each list is a format string to format the
150
+ postamble itself. This format string can contain these elements:
151
+
152
+ %t stands for the title.
153
+ %s stands for the subtitle.
154
+ %a stands for the author's name.
155
+ %e stands for the author's email.
156
+ %d stands for the date.
157
+ %k stands for the keywords list.
158
+ %l stands for the language code name.
159
+ %x stands for the description.
160
+ %c will be replaced by `org-gmi-creator-string'.
161
+ %T will be replaced by the export time.
162
+ %C will be replaced by the last modification time.
163
+
164
+ If you need to use a \"%\" character, you need to escape it
165
+ like that: \"%%\"."
166
+ :group 'org-export-gmi
167
+ :type '(repeat
168
+ (list (string :tag "Language")
169
+ (string :tag "Format string"))))
170
+
171
+ (defcustom org-gmi-creator-string
172
+ (format "GNU/Emacs %s (Org mode %s)"
173
+ emacs-version
174
+ (if (fboundp 'org-version) (org-version) "unknown version"))
175
+ "Information about the creator of the Gemini document.
176
+ This option can also be set on with the CREATOR keyword."
177
+ :group 'org-export-gmi
178
+ :type '(string :tag "Creator string"))
179
+
180
+ (defcustom org-gmi-timestamp-format "%Y-%m-%d %a %H:%M"
181
+ "Format used for timestamps in postamble.
182
+ See `format-time-string' for more information on its components."
183
+ :group 'org-export-gmi
184
+ :type 'string)
185
+
186
+
187
+
188
+ ;;; Inner Functions
189
+
190
+ (defun org-gmi--build-headline (level title &optional tags)
191
+ "Generate a headline TITLE for the given LEVEL.
192
+ TAGS are the tags set on the section."
193
+ (let ((level-mark (make-string level ?#)))
194
+ (concat level-mark " " title tags "\n\n")))
195
+
196
+ (defun org-gmi--build-links-list (links)
197
+ "Return a string describing a list of links.
198
+ LINKS is an alist like `org-gmi--links-in-section'"
199
+ (let (links-list)
200
+ (string-trim-right
201
+ (apply #'concat
202
+ (reverse
203
+ (dolist (link-data links links-list)
204
+ (push (apply #'org-gmi--format-link link-data)
205
+ links-list)))))))
206
+
207
+ (defun org-gmi--build-toc (info &optional depth)
208
+ "Return a table of contents.
209
+ INFO is a plist used as a communication channel.
210
+ Optional argument DEPTH, when non-nil, is an integer specifying the
211
+ depth of the table."
212
+ (mapconcat
213
+ (lambda (headline)
214
+ (let* ((prefix
215
+ (if (not (org-export-numbered-headline-p headline info)) ""
216
+ (concat
217
+ (mapconcat 'number-to-string
218
+ (org-export-get-headline-number headline info)
219
+ ".")
220
+ ". ")))
221
+ (title (org-export-data-with-backend
222
+ (org-export-get-alt-title headline info)
223
+ (org-export-toc-entry-backend 'gmi)
224
+ info))
225
+ (tags (and (plist-get info :with-tags)
226
+ (not (eq 'not-in-toc (plist-get info :with-tags)))
227
+ (org-make-tag-string
228
+ (org-export-get-tags headline info)))))
229
+ (concat prefix title tags)))
230
+ (org-export-collect-headlines info depth) "\n"))
231
+
232
+ (defun org-gmi--build-postamble (info)
233
+ "Return document postamble as a string, or nil.
234
+ INFO is a plist used as a communication channel."
235
+ (let ((section (plist-get info :gemini-postamble))
236
+ (spec (org-gmi--format-spec info)))
237
+ (when section
238
+ (let ((section-contents
239
+ (if (functionp section) (funcall section info)
240
+ (cond
241
+ ((stringp section) (format-spec section spec))
242
+ ((eq section 'auto)
243
+ (let ((date (cdr (assq ?d spec)))
244
+ (author (cdr (assq ?a spec)))
245
+ (email (cdr (assq ?e spec)))
246
+ (creator (cdr (assq ?c spec))))
247
+ (concat
248
+ (and (plist-get info :with-date)
249
+ (org-string-nw-p date)
250
+ (format "📅 %s\n" date))
251
+ (and (plist-get info :with-author)
252
+ (org-string-nw-p author)
253
+ (format "📝 %s\n" author))
254
+ (and (plist-get info :with-email)
255
+ (org-string-nw-p email)
256
+ (format "💌 %s\n" email))
257
+ (and (plist-get info :time-stamp-file)
258
+ (format
259
+ "🕓 %s\n"
260
+ (format-time-string
261
+ (plist-get info :gemini-timestamp-format))))
262
+ (and (plist-get info :with-creator)
263
+ (org-string-nw-p creator)
264
+ (format "⚙ %s\n" creator)))))
265
+ (t
266
+ (let ((formats (plist-get info :gemini-postamble-format))
267
+ (language (plist-get info :language)))
268
+ (format-spec
269
+ (cadr (or (assoc-string language formats t)
270
+ (assoc-string "en" formats t)))
271
+ spec)))))))
272
+ (when (org-string-nw-p section-contents)
273
+ (format "\n\n--\n%s\n"
274
+ (org-element-normalize-string section-contents)))))))
275
+
276
+ (defun org-gmi--format-spec (info)
277
+ "Return format specification for postamble.
278
+ INFO is a plist used as a communication channel."
279
+ (let ((timestamp-format (plist-get info :gemini-timestamp-format)))
280
+ `((?t . ,(org-export-data (plist-get info :title) info))
281
+ (?s . ,(org-export-data (plist-get info :subtitle) info))
282
+ (?d . ,(org-export-data (org-export-get-date info timestamp-format) info))
283
+ (?T . ,(format-time-string timestamp-format))
284
+ (?a . ,(org-export-data (plist-get info :author) info))
285
+ (?e . ,(org-export-data (plist-get info :email) info))
286
+ (?c . ,(plist-get info :creator))
287
+ (?C . ,(let ((file (plist-get info :input-file)))
288
+ (format-time-string
289
+ timestamp-format
290
+ (and file (file-attribute-modification-time
291
+ (file-attributes file))))))
292
+ (?k . ,(org-export-data (plist-get info :keywords) info))
293
+ (?l . ,(org-export-data (plist-get info :language) info))
294
+ (?x . ,(org-export-data (plist-get info :description) info)))))
295
+
296
+ (defun org-gmi--format-paragraph (paragraph &optional prefix)
297
+ "Transcode PARAGRAPH into Gemini format.
298
+ If PREFIX is non-nil, add it at the beginning of each lines."
299
+ (replace-regexp-in-string
300
+ "^\\s-?" (or prefix "")
301
+ (org-trim
302
+ (replace-regexp-in-string "\r?\n\\([^\r\n]\\)" " \\1" paragraph))))
303
+
304
+ (defun org-gmi--format-link (dest label &optional reference)
305
+ "Return a formatted link pointing to DEST with the given LABEL.
306
+
307
+ When REFERENCE is given, it is added between bracket to generate single link
308
+ entry in a links list."
309
+ (if reference
310
+ (format "=> %s [%d] %s\n" dest reference label)
311
+ (format "=> %s %s\n" dest label)))
312
+
313
+ (defun org-gmi--link-alone-on-line-p (link)
314
+ "Return t if the given LINK occupies its whole line."
315
+ (let* ((link-start (org-element-property :begin link))
316
+ (link-end (org-element-property :end link))
317
+ (full-link (buffer-substring-no-properties link-start link-end))
318
+ (raw-link (org-element-property :raw-link link)))
319
+ (save-excursion
320
+ (org-goto-line (org-current-line link-start))
321
+ (let ((line-content (org-trim (thing-at-point 'line t))))
322
+ (or (string= raw-link line-content)
323
+ (string= full-link line-content))))))
324
+
325
+ (defun org-gmi--extract-picture-label (link info)
326
+ "Extract a worthy label for the given LINK, when HREF points to a picture."
327
+ (let* ((paragraph (org-element-parent link))
328
+ (alt (plist-get
329
+ (org-export-read-attribute :attr_gmi paragraph)
330
+ :alt))
331
+ (caption (org-export-data (org-export-get-caption paragraph) info)))
332
+ (if (org-string-nw-p caption)
333
+ caption
334
+ alt)))
335
+
336
+ (defun org-gmi--number-to-utf8-exponent (number)
337
+ "Convert a NUMBER to its utf8 exponent display."
338
+ (let ((exponents '((?1 . "¹")
339
+ (?2 . "²")
340
+ (?3 . "³")
341
+ (?4 . "⁴")
342
+ (?5 . "⁵")
343
+ (?6 . "⁶")
344
+ (?7 . "⁷")
345
+ (?8 . "⁸")
346
+ (?9 . "⁹")
347
+ (?0 . "⁰"))))
348
+ (mapconcat
349
+ (lambda (digit) (cdr (assoc digit exponents)))
350
+ (number-to-string number)
351
+ "")))
352
+
353
+
354
+ ;;; Transcode Functions
355
+
356
+ (defun org-gmi-preformatted-block (block _contents info)
357
+ "Transcode BLOCK element into Gemini format.
358
+ INFO is a plist used as a communication channel."
359
+ (let ((language (org-export-data (org-element-property :language block) info))
360
+ (caption (org-export-data (org-export-get-caption block) info)))
361
+ (setq caption (if (org-string-nw-p caption)
362
+ (format "%s - %s" language caption)
363
+ language))
364
+ (format "```%s\n%s```\n"
365
+ caption
366
+ (org-remove-indentation
367
+ (org-export-format-code-default block info)))))
368
+
369
+ (defun org-gmi-export-block (export-block _contents _info)
370
+ "Transcode a EXPORT-BLOCK element from Org to Gemini."
371
+ (if (member (org-element-property :type export-block) '("GEMINI" "GMI"))
372
+ (org-remove-indentation (org-element-property :value export-block))))
373
+
374
+ (defun org-gmi-center (_center contents info)
375
+ "Transcode a CENTER block from Org to Gemini.
376
+ CONTENTS is the block value. INFO is a plist holding contextual
377
+ information."
378
+ (format "```\n%s```"
379
+ (org-ascii--fill-string contents 80 info 'center)))
380
+
381
+ (defun org-gmi-entity (_entity contents _info)
382
+ "Transcode an ENTITY object from Org to Gemini.
383
+ CONTENTS is the entity itself."
384
+ contents)
385
+
386
+ (defun org-gmi-footnote-reference (footnote-reference _contents info)
387
+ "Transcode a FOOTNOTE-REFERENCE element from Org to Gemini.
388
+ CONTENTS is nil. INFO is a plist holding contextual information."
389
+ (org-gmi--number-to-utf8-exponent
390
+ (org-export-get-footnote-number footnote-reference info)))
391
+
392
+ (defun org-gmi-headline (headline contents info)
393
+ "Transcode HEADLINE element into Gemini format.
394
+ CONTENTS is the headline value. INFO is a plist used as
395
+ a communication channel."
396
+ (let* ((level (1+ (org-export-get-relative-level headline info)))
397
+ (title (org-export-data (org-element-property :title headline) info))
398
+ (todo (and (plist-get info :with-todo-keywords)
399
+ (let ((todo (org-element-property :todo-keyword
400
+ headline)))
401
+ (and todo (concat (org-export-data todo info) " ")))))
402
+ (tags (and (plist-get info :with-tags)
403
+ (let ((tag-list (org-export-get-tags headline info)))
404
+ (and tag-list
405
+ (concat " " (org-make-tag-string tag-list))))))
406
+ (priority
407
+ (and (plist-get info :with-priority)
408
+ (let ((char (org-element-property :priority headline)))
409
+ (and char (format "[#%c] " char)))))
410
+ ;; Headline text without tags.
411
+ (heading (concat todo priority title)))
412
+ (if
413
+ ;; Cannot create a headline. Fall-back to a list.
414
+ (or (org-export-low-level-p headline info)
415
+ (> level 3)) ;; Gemtext only allow 3 levels of title
416
+ (let ((bullet
417
+ (if (not (org-export-numbered-headline-p headline info)) "*"
418
+ (concat (number-to-string
419
+ (car (last (org-export-get-headline-number
420
+ headline info))))
421
+ "."))))
422
+ (concat bullet (make-string (- 4 (length bullet)) ?\s)
423
+ heading tags "\n\n" contents))
424
+ ;; Else
425
+ (concat (org-gmi--build-headline level heading tags) contents))))
426
+
427
+ (defun org-gmi-inner-template (contents info)
428
+ "Return body of document after converting it to Gemini syntax.
429
+ CONTENTS is the transcoded contents string. INFO is a plist
430
+ holding export options."
431
+ (concat
432
+ ;; Document contents.
433
+ contents
434
+ ;; Footnotes section.
435
+ (let ((definitions (org-export-collect-footnote-definitions info)))
436
+ (when definitions
437
+ (concat
438
+ "\n\n"
439
+ (org-gmi--build-headline
440
+ 2 (org-ascii--translate "Footnotes" info))
441
+ (mapconcat
442
+ (lambda (ref)
443
+ (let ((id (car ref))
444
+ (def (nth 2 ref)))
445
+ (format "%s %s" (org-gmi--number-to-utf8-exponent id)
446
+ (replace-regexp-in-string
447
+ "\r?\n" " "
448
+ (org-trim (org-export-data def info))))))
449
+ definitions "\n\n"))))))
450
+
451
+ (defun org-gmi-template (contents info)
452
+ "Return body of document after converting it to Gemini syntax.
453
+ CONTENTS is the transcoded contents string. INFO is a plist
454
+ holding export options."
455
+ (concat
456
+ ;; Document title.
457
+ (org-gmi--build-headline
458
+ 1 (org-export-data (plist-get info :title) info))
459
+ ;; TOC
460
+ (let* ((depth (plist-get info :with-toc))
461
+ (toc-contents (when depth
462
+ (org-gmi--build-toc
463
+ info (and (wholenump depth) depth)))))
464
+ (when (org-string-nw-p toc-contents)
465
+ (concat
466
+ (org-gmi--build-headline 2 (org-ascii--translate "Table of Contents" info))
467
+ toc-contents
468
+ "\n\n\n")))
469
+ ;; Document contents.
470
+ contents
471
+ ;; Postamble
472
+ (org-gmi--build-postamble info)))
473
+
474
+ (defun org-gmi-item (item contents info)
475
+ "Transcode ITEM element into Gemini format.
476
+ CONTENTS is the item value. INFO is a plist used as a
477
+ communication channel."
478
+ (let* ((type (org-element-property :type (org-export-get-parent item)))
479
+ (struct (org-element-property :structure item))
480
+ (bullet (if (not (eq type 'ordered)) "*"
481
+ (concat (number-to-string
482
+ (car (last (org-list-get-item-number
483
+ (org-element-property :begin item)
484
+ struct
485
+ (org-list-prevs-alist struct)
486
+ (org-list-parents-alist struct)))))
487
+ "."))))
488
+ (concat bullet
489
+ " "
490
+ (pcase (org-element-property :checkbox item)
491
+ (`on "[X] ")
492
+ (`trans "[-] ")
493
+ (`off "[ ] "))
494
+ (let ((tag (org-element-property :tag item)))
495
+ (and tag (format "%s: " (org-export-data tag info))))
496
+ (and contents (org-trim contents)))))
497
+
498
+ (defun org-gmi-keyword (keyword _contents _info)
499
+ "Transcode a KEYWORD element into Gemini format.
500
+ CONTENTS is nil. INFO is a plist used as a communication
501
+ channel."
502
+ (when (member (org-element-property :key keyword) '("GEMINI" "GMI"))
503
+ (org-element-property :value keyword)))
504
+
505
+ (defun org-gmi-line-break (_line-break _contents _info)
506
+ "Transcode LINE-BREAK object into Gemini format.
507
+ CONTENTS is nil. INFO is a plist used as a communication
508
+ channel."
509
+ " ")
510
+
511
+ (defun org-gmi-link (link desc info)
512
+ "Transcode a LINK object from Org to Gemini.
513
+ DESC is the description part of the link, or the empty string."
514
+ (let ((link-type (org-element-property :type link))
515
+ (link-path (org-element-property :path link))
516
+ href lang)
517
+ ;; Cleanup path
518
+ (setq href
519
+ (if (member link-type '("file" "fuzzy"))
520
+ (if (string= ".org" (downcase (file-name-extension link-path ".")))
521
+ ;; Replace local org file to gmi files during publication
522
+ (format "%s.gmi" (file-name-sans-extension link-path))
523
+ link-path)
524
+ (org-element-property :raw-link link)))
525
+ (when (string= (substring href 0 5) "i18n:")
526
+ (pcase-let ((`(,path ,raw-lang) (split-string (substring href 5) "::")))
527
+ (setq href path lang raw-lang)))
528
+ (let* ((scheme (car (split-string href ":" t)))
529
+ ;; Avoid cut lines in link labels
530
+ (raw-label (replace-regexp-in-string "\r?\n" " " (or desc href)))
531
+ (label (if (and (not (member href (list desc scheme))) ;; relative link
532
+ (not (member (downcase scheme)
533
+ '("gemini" "file"))))
534
+ (format "%s (%s)" raw-label (upcase scheme))
535
+ raw-label)))
536
+ (when lang (setq label (format "%s [%s]" label lang)))
537
+ ;; Handle pictures
538
+ (let* ((dest-ext (file-name-extension href))
539
+ (found-label
540
+ (when (and (not desc)
541
+ (member (or (and dest-ext (downcase dest-ext)) "")
542
+ '("jpeg" "jpg" "png" "gif" "svg" "webp" "avif")))
543
+ (org-gmi--extract-picture-label link info))))
544
+ (when found-label (setq label found-label)))
545
+ ;; Do we need to add the link at the end of the section or should it be
546
+ ;; directly printed in its own line?
547
+ (if (org-gmi--link-alone-on-line-p link)
548
+ (org-gmi--format-link href label)
549
+ ;; As links are specific for a section, which should not be that long (?),
550
+ ;; we will always use the first label encountered for a link as
551
+ ;; reference.
552
+ (let ((link-data (assoc href org-gmi--links-in-section)))
553
+ (unless link-data
554
+ (setq link-data (list href label
555
+ ;; Default next-reference
556
+ (1+ (length org-gmi--links-in-section))))
557
+ (add-to-list 'org-gmi--links-in-section link-data t))
558
+ (format "%s[%d]" raw-label (caddr link-data)))))))
559
+
560
+ (defun org-gmi-paragraph (_paragraph contents _info)
561
+ "Transcode PARAGRAPH element into Gemini format.
562
+ CONTENTS is the paragraph value."
563
+ (org-gmi--format-paragraph contents))
564
+
565
+ (defun org-gmi-quote-block (_quote-block contents _info)
566
+ "Transcode QUOTE-BLOCK element into Gemini format.
567
+ CONTENTS is the quote-block value."
568
+ (org-gmi--format-paragraph contents "> "))
569
+
570
+ (defun org-gmi-section (_section contents _info)
571
+ "Transcode SECTION into Gemini format.
572
+ CONTENTS is the section value."
573
+ (let ((output
574
+ (format "%s\n%s"
575
+ contents
576
+ (org-gmi--build-links-list org-gmi--links-in-section))))
577
+ (setq org-gmi--links-in-section '()) ;; Reset link list
578
+ output))
579
+
580
+
581
+ ;;; Interactive function
582
+
583
+ ;;;###autoload
584
+ (defun org-gmi-export-as-gemini (&optional async subtreep visible-only)
585
+ "Export current buffer to a Gemini buffer.
586
+
587
+ If narrowing is active in the current buffer, only export its
588
+ narrowed part.
589
+
590
+ If a region is active, export that region.
591
+
592
+ A non-nil optional argument ASYNC means the process should happen
593
+ asynchronously. The resulting buffer should be accessible
594
+ through the `org-export-stack' interface.
595
+
596
+ When optional argument SUBTREEP is non-nil, export the sub-tree
597
+ at point, extracting information from the headline properties
598
+ first.
599
+
600
+ When optional argument VISIBLE-ONLY is non-nil, don't export
601
+ contents of hidden elements.
602
+
603
+ Export is done in a buffer named \"*Org Gemini Export*\", which will
604
+ be displayed when `org-export-show-temporary-export-buffer' is
605
+ non-nil."
606
+ (interactive)
607
+ (org-export-to-buffer
608
+ 'gmi "*Org Gemini Export*"
609
+ async subtreep visible-only nil nil
610
+ (lambda ()
611
+ (if (featurep 'gemini-mode)
612
+ (gemini-mode)
613
+ (text-mode)))))
614
+
615
+ ;;;###autoload
616
+ (defun org-gmi-export-to-gemini (&optional async subtreep visible-only)
617
+ "Export current buffer to a Gemini file.
618
+
619
+ If narrowing is active in the current buffer, only export its
620
+ narrowed part.
621
+
622
+ If a region is active, export that region.
623
+
624
+ A non-nil optional argument ASYNC means the process should happen
625
+ asynchronously. The resulting file should be accessible through
626
+ the `org-export-stack' interface.
627
+
628
+ When optional argument SUBTREEP is non-nil, export the sub-tree
629
+ at point, extracting information from the headline properties
630
+ first.
631
+
632
+ When optional argument VISIBLE-ONLY is non-nil, don't export
633
+ contents of hidden elements.
634
+
635
+ Return output file's name."
636
+ (interactive)
637
+ (let ((outfile (org-export-output-file-name ".gmi" subtreep)))
638
+ (org-export-to-file 'gmi outfile async subtreep visible-only)))
639
+
640
+
641
+ ;;;###autoload
642
+ (defun org-gmi-publish-to-gemini (plist filename pub-dir)
643
+ "Publish an org file to Gemini.
644
+
645
+ FILENAME is the filename of the Org file to be published. PLIST
646
+ is the property list for the given project. PUB-DIR is the
647
+ publishing directory.
648
+
649
+ Return output file name."
650
+ (org-publish-org-to 'gmi filename ".gmi" plist pub-dir))
651
+
652
+ (provide 'ox-gmi)
653
+
654
+ ;;; ox-gmi.el ends here
@@ -59,4 +59,4 @@ module Fronde
59
59
  end
60
60
  end
61
61
 
62
- Liquid::Template.register_filter(Fronde::Config::Filters)
62
+ Liquid::Environment.default.register_filter(Fronde::Config::Filters)
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'json'
4
- require 'open-uri'
5
4
  require_relative '../version'
6
5
  require_relative '../org'
7
6
  require_relative 'helpers'
@@ -11,6 +10,19 @@ module Fronde
11
10
  # This module contains utilitary methods to ease ~org-config.el~
12
11
  # file generation
13
12
  module Lisp
13
+ class << self
14
+ def theme_directory(theme)
15
+ # User theme first to allow overwriting
16
+ directory = File.expand_path("themes/#{theme}")
17
+ return directory if Dir.exist? directory
18
+
19
+ directory = File.expand_path("data/themes/#{theme}", __dir__)
20
+ return directory if Dir.exist? directory
21
+
22
+ raise Errno::ENOENT, "Theme #{theme} not found"
23
+ end
24
+ end
25
+
14
26
  # Generate emacs lisp configuration file for Org and write it.
15
27
  #
16
28
  # This method saves the generated configuration in the file
@@ -41,19 +53,8 @@ module Fronde
41
53
 
42
54
  private
43
55
 
44
- def theme_directory(theme)
45
- # User theme first to allow overwriting
46
- directory = File.expand_path("themes/#{theme}")
47
- return directory if Dir.exist? directory
48
-
49
- directory = File.expand_path("data/themes/#{theme}", __dir__)
50
- return directory if Dir.exist? directory
51
-
52
- raise Errno::ENOENT, "Theme #{theme} not found"
53
- end
54
-
55
56
  def org_theme_config(theme)
56
- { 'base-directory' => theme_directory(theme),
57
+ { 'base-directory' => Lisp.theme_directory(theme),
57
58
  # rubocop:disable Layout/LineLength
58
59
  'base-extension' => %w[css js gif jpg png svg otf ttf woff2?].join('\\\\|'),
59
60
  'publishing-directory' => "#{get('html_public_folder')}/assets/#{theme}",
@@ -34,21 +34,16 @@ module Fronde
34
34
  # @param entries [Array] the article to list in this file
35
35
  # @return [String] the Atom feed as a String
36
36
  def atom_file(tag_name, entries)
37
- domain = Fronde::CONFIG.get('domain')
38
37
  slug = Slug.slug(tag_name)
39
- tagurl = "#{domain}#{@project.public_absolute_path}tags/#{slug}.html"
40
- Config::Helpers.render_liquid_template(
41
- File.read(File.expand_path('./data/template.xml', __dir__)),
38
+ variables = atom_templating_basics.merge(
42
39
  'title' => @tags_names[tag_name],
43
- 'lang' => Fronde::CONFIG.get('lang'),
44
- 'domain' => domain,
45
40
  'slug' => slug,
46
- 'tagurl' => tagurl,
47
- 'upddate' => @date.xmlschema,
48
- 'author' => Fronde::CONFIG.get('author'),
49
- 'publication_format' => @project['mime_type'],
50
41
  'entries' => entries
51
42
  )
43
+ Config::Helpers.render_liquid_template(
44
+ File.read(File.expand_path('./data/template.xml', __dir__)),
45
+ variables
46
+ )
52
47
  end
53
48
 
54
49
  # Render the main/index Atom feed.
@@ -56,19 +51,26 @@ module Fronde
56
51
  # @param entries [Array] the article to list in this file
57
52
  # @return [String] the Atom feed as a String
58
53
  def atom_index(entries)
59
- domain = Fronde::CONFIG.get('domain')
54
+ variables = atom_templating_basics.merge(
55
+ 'title' => @project['title'],
56
+ 'slug' => '__HOME_PAGE__',
57
+ 'entries' => entries
58
+ )
60
59
  Config::Helpers.render_liquid_template(
61
60
  File.read(File.expand_path('./data/template.xml', __dir__)),
62
- 'title' => @project['title'],
61
+ variables
62
+ )
63
+ end
64
+
65
+ def atom_templating_basics
66
+ {
63
67
  'lang' => Fronde::CONFIG.get('lang'),
64
- 'domain' => domain,
65
- 'slug' => 'index',
66
- 'tagurl' => domain,
67
- 'upddate' => @date.xmlschema,
68
68
  'author' => Fronde::CONFIG.get('author'),
69
- 'publication_format' => @project['mime_type'],
70
- 'entries' => entries
71
- )
69
+ 'domain' => Fronde::CONFIG.get('domain'),
70
+ 'project_path' => @project.public_absolute_path,
71
+ 'upddate' => @date.xmlschema,
72
+ 'publication_format' => @project['mime_type']
73
+ }
72
74
  end
73
75
  end
74
76
  end
@@ -4,12 +4,17 @@
4
4
  xml:lang="{{ lang }}">
5
5
 
6
6
  <title>{{ title | escape }}</title>
7
- <link href="{{ domain }}/feeds/{{ slug }}.xml" rel="self" type="application/atom+xml"/>
8
- <link href="{{ tagurl }}" rel="alternate" type="text/html" title="{{ title }}"/>
7
+ {%- if slug == "__HOME_PAGE__" %}
8
+ <link href="{{ domain }}{{ project_path }}feeds/index.xml" rel="self" type="application/atom+xml"/>
9
+ <link href="{{ domain }}" rel="alternate" type="text/html" title="{{ title | escape }}"/>
10
+ {%- else %}
11
+ <link href="{{ domain }}{{ project_path }}feeds/{{ slug }}.xml" rel="self" type="application/atom+xml"/>
12
+ <link href="{{ domain }}{{ project_path }}tags/{{ slug }}.html" rel="alternate" type="text/html" title="{{ title | escape }}"/>
13
+ {%- endif %}
9
14
  <updated>{{ upddate }}</updated>
10
15
  <author><name>{{ author }}</name></author>
11
16
  <id>urn:md5:{{ domain | md5 }}</id>
12
- <generator uri="https://git.umaneti.net/fronde/about/">Fronde</generator>
17
+ <generator uri="https://git.umaneti.net/fronde">Fronde</generator>
13
18
 
14
19
  {%- for article in entries %}
15
20
 
@@ -17,7 +22,7 @@
17
22
  <title>{{ article.title | escape }}</title>
18
23
  <link href="{{ article.url }}" rel="alternate"
19
24
  type="{{ publication_format }}"
20
- title="{{ article.title }}"/>
25
+ title="{{ article.title | escape }}"/>
21
26
  <id>urn:md5:{{ article.timekey | md5 }}</id>
22
27
  <published>{{ article.published_xml }}</published>
23
28
  <updated>{{ article.updated_xml }}</updated>
@@ -193,7 +193,7 @@ module Fronde
193
193
  .gsub('%l', @data[:lang])
194
194
  .gsub('%L', Fronde::CONFIG.get('license', '').gsub(/\s+/, ' ').strip)
195
195
  .gsub('%n', "Fronde #{Fronde::VERSION}")
196
- .gsub('%N', "<a href=\"https://git.umaneti.net/fronde/about/\">Fronde</a> #{Fronde::VERSION}")
196
+ .gsub('%N', "<a href=\"https://git.umaneti.net/fronde\">Fronde</a> #{Fronde::VERSION}")
197
197
  .gsub('%o', project_data['theme'] || '')
198
198
  .gsub('%s', @data[:subtitle])
199
199
  .gsub('%t', @data[:title])
data/lib/fronde/org.rb CHANGED
@@ -1,5 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'net/http'
4
+ require_relative 'version'
5
+
3
6
  module Fronde
4
7
  # Everything related to Org mode
5
8
  #
@@ -7,6 +10,8 @@ module Fronde
7
10
  # of the Emacs package. It also serves as a namespace for the class
8
11
  # responsible for handling Org files: {Fronde::Org::File}.
9
12
  module Org
13
+ CGIT_BASE_URL = 'https://cgit.git.savannah.gnu.org/cgit/emacs/org-mode.git/'
14
+
10
15
  class << self
11
16
  def current_version
12
17
  # Do not crash if Org is not yet installed (and thus return nil)
@@ -36,18 +41,26 @@ module Fronde
36
41
  org_version
37
42
  end
38
43
 
44
+ def http_get_client(uri)
45
+ Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
46
+ request = Net::HTTP::Get.new(uri)
47
+ request['User-Agent'] = Fronde::USER_AGENT
48
+ yield http, request
49
+ end
50
+ end
51
+
39
52
  def fetch_version_number
40
53
  # Retrieve last org version from git repository tags page.
41
54
  tag_rx = Regexp.new(
42
55
  '<a href=\'/cgit/emacs/org-mode.git/tag/\?h=' \
43
56
  '(?<tag>release_(?<number>[^\']+))\'>\k<tag></a>'
44
57
  )
45
- versions = URI(
46
- 'https://git.savannah.gnu.org/cgit/emacs/org-mode.git/refs/'
47
- ).open.readlines.map do |line|
58
+ uri = URI(CGIT_BASE_URL)
59
+ response = http_get_client(uri) { |http, req| http.request req }
60
+ versions = response.body.each_line(chomp: true).filter_map do |line|
48
61
  line.match(tag_rx) { |matchdata| matchdata[:number] }
49
62
  end
50
- versions.compact.first
63
+ versions.compact.max_by { Gem::Version.new _1 }
51
64
  end
52
65
 
53
66
  # Download latest org-mode tarball.
@@ -57,10 +70,10 @@ module Fronde
57
70
  def download(destination = 'var/tmp')
58
71
  org_last_version = last_version(force: false, cookie_dir: destination)
59
72
  tarball = "org-mode-release_#{org_last_version}.tar.gz"
60
- uri = URI("https://git.savannah.gnu.org/cgit/emacs/org-mode.git/snapshot/#{tarball}")
73
+ uri = URI("#{CGIT_BASE_URL}snapshot/#{tarball}")
61
74
  # Will crash on purpose if anything goes wrong
62
- Net::HTTP.start(uri.host) do |http|
63
- fetch_org_tarball http, Net::HTTP::Get.new(uri), destination
75
+ http_get_client(uri) do |http, request|
76
+ fetch_org_tarball http, request, destination
64
77
  end
65
78
  org_last_version
66
79
  end
@@ -2,5 +2,9 @@
2
2
 
3
3
  module Fronde
4
4
  # @return [String] the version number of the current Fronde release.
5
- VERSION = '0.6.1'
5
+ VERSION = '0.6.3'
6
+
7
+ USER_AGENT = ["Fronde/#{Fronde::VERSION}",
8
+ "(#{RUBY_ENGINE} #{RUBY_VERSION} #{RUBY_PLATFORM})",
9
+ '(+https://etienne.pflieger.bzh/fronde/)'].join(' ').freeze
6
10
  end
data/lib/tasks/org.rake CHANGED
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'open-uri'
4
-
5
3
  require_relative '../fronde/config'
6
4
  require_relative '../fronde/cli/throbber'
7
5
 
@@ -12,7 +10,6 @@ CLOBBER.push(
12
10
  )
13
11
 
14
12
  HTMLIZE_TAG = 'release/1.58'
15
- OX_GMI_TAG = 'v0.2'
16
13
 
17
14
  namespace :org do
18
15
  directory 'var/tmp'
@@ -57,20 +54,18 @@ namespace :org do
57
54
  directory 'lib'
58
55
 
59
56
  file 'lib/htmlize.el' => 'lib' do
60
- htmlize = URI(
57
+ uri = URI(
61
58
  "https://raw.githubusercontent.com/hniksic/emacs-htmlize/refs/tags/#{HTMLIZE_TAG}/htmlize.el"
62
- ).open.read
63
- File.write 'lib/htmlize.el', htmlize
64
- end
65
-
66
- file 'lib/ox-gmi.el' => 'lib' do
67
- ox_gmi = URI(
68
- "https://git.umaneti.net/ox-gmi/plain/ox-gmi.el?h=#{OX_GMI_TAG}"
69
- ).open.read
70
- File.write 'lib/ox-gmi.el', ox_gmi
59
+ )
60
+ response = Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
61
+ request = Net::HTTP::Get.new(uri)
62
+ request['User-Agent'] = Fronde::USER_AGENT
63
+ http.request request
64
+ end
65
+ File.write 'lib/htmlize.el', response.body
71
66
  end
72
67
 
73
- file 'var/lib/org-config.el' => ['lib/htmlize.el', 'lib/ox-gmi.el'] do
68
+ file 'var/lib/org-config.el' => ['lib/htmlize.el'] do
74
69
  Fronde::CONFIG.write_org_lisp_config
75
70
  end
76
71
 
@@ -85,9 +80,9 @@ namespace :org do
85
80
 
86
81
  desc 'Install Org'
87
82
  multitask install: ['org:compile', '.gitignore'] do
88
- # lib/htmlize.el and lib/ox-gmi.el cannot be generated in parallel
89
- # of org:compilation, as it will leads to a weird SSL error. Thus
90
- # finishing file generation "manually" here.
83
+ # lib/htmlize.el cannot be generated in parallel of org:compilation,
84
+ # as it will leads to a weird SSL error. Thus finishing file generation
85
+ # "manually" here.
91
86
  Rake::Task['var/lib/org-config.el'].invoke
92
87
  sources = Fronde::CONFIG.sources
93
88
  sources.each { mkdir_p _1['path'] }
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fronde
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.1
4
+ version: 0.6.3
5
5
  platform: ruby
6
6
  authors:
7
- - Étienne Deparis
8
- autorequire:
7
+ - Étienne Pflieger
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2024-11-05 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: base64
@@ -58,28 +57,28 @@ dependencies:
58
57
  requirements:
59
58
  - - "~>"
60
59
  - !ruby/object:Gem::Version
61
- version: '5.5'
60
+ version: '5.8'
62
61
  type: :runtime
63
62
  prerelease: false
64
63
  version_requirements: !ruby/object:Gem::Requirement
65
64
  requirements:
66
65
  - - "~>"
67
66
  - !ruby/object:Gem::Version
68
- version: '5.5'
67
+ version: '5.8'
69
68
  - !ruby/object:Gem::Dependency
70
69
  name: nokogiri
71
70
  requirement: !ruby/object:Gem::Requirement
72
71
  requirements:
73
72
  - - "~>"
74
73
  - !ruby/object:Gem::Version
75
- version: '1.16'
74
+ version: '1.18'
76
75
  type: :runtime
77
76
  prerelease: false
78
77
  version_requirements: !ruby/object:Gem::Requirement
79
78
  requirements:
80
79
  - - "~>"
81
80
  - !ruby/object:Gem::Version
82
- version: '1.16'
81
+ version: '1.18'
83
82
  - !ruby/object:Gem::Dependency
84
83
  name: rainbow
85
84
  requirement: !ruby/object:Gem::Requirement
@@ -100,28 +99,28 @@ dependencies:
100
99
  requirements:
101
100
  - - "~>"
102
101
  - !ruby/object:Gem::Version
103
- version: '13.1'
102
+ version: '13.2'
104
103
  type: :runtime
105
104
  prerelease: false
106
105
  version_requirements: !ruby/object:Gem::Requirement
107
106
  requirements:
108
107
  - - "~>"
109
108
  - !ruby/object:Gem::Version
110
- version: '13.1'
109
+ version: '13.2'
111
110
  - !ruby/object:Gem::Dependency
112
111
  name: webrick
113
112
  requirement: !ruby/object:Gem::Requirement
114
113
  requirements:
115
114
  - - "~>"
116
115
  - !ruby/object:Gem::Version
117
- version: '1.8'
116
+ version: '1.9'
118
117
  type: :runtime
119
118
  prerelease: false
120
119
  version_requirements: !ruby/object:Gem::Requirement
121
120
  requirements:
122
121
  - - "~>"
123
122
  - !ruby/object:Gem::Version
124
- version: '1.8'
123
+ version: '1.9'
125
124
  description: |
126
125
  Fronde helps you to convert Org mode files into websites, giving you
127
126
  full control over the publication process.
@@ -149,6 +148,7 @@ files:
149
148
  - lib/fronde/config.rb
150
149
  - lib/fronde/config/data/org-config.el
151
150
  - lib/fronde/config/data/ox-fronde.el
151
+ - lib/fronde/config/data/ox-gmi.el
152
152
  - lib/fronde/config/data/themes/umaneti/css/htmlize.css
153
153
  - lib/fronde/config/data/themes/umaneti/css/style.css
154
154
  - lib/fronde/config/data/themes/umaneti/img/bottom.png
@@ -184,13 +184,13 @@ files:
184
184
  - lib/tasks/tags.rake
185
185
  - locales/en.yml
186
186
  - locales/fr.yml
187
- homepage: https://git.umaneti.net/fronde/about/
187
+ homepage: https://etienne.pflieger.bzh/fronde/
188
188
  licenses:
189
189
  - WTFPL
190
190
  metadata:
191
191
  rubygems_mfa_required: 'true'
192
192
  source_code_uri: https://git.umaneti.net/fronde
193
- homepage_uri: https://etienne.depar.is/fronde/
193
+ homepage_uri: https://etienne.pflieger.bzh/fronde/
194
194
  funding_uri: https://liberapay.com/milouse
195
195
  post_install_message: |+
196
196
  Start your first fronde project with:
@@ -217,8 +217,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
217
217
  version: '0'
218
218
  requirements:
219
219
  - emacs
220
- rubygems_version: 3.5.22
221
- signing_key:
220
+ rubygems_version: 3.7.2
222
221
  specification_version: 4
223
222
  summary: An opinionated static website generator for Org
224
223
  test_files: []