fronde 0.4.0 → 0.6.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.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/lib/ext/nil_time.rb +3 -6
  3. data/lib/ext/time.rb +10 -17
  4. data/lib/ext/time_no_time.rb +27 -0
  5. data/lib/fronde/cli/commands.rb +18 -14
  6. data/lib/fronde/cli/data/fish_completion +20 -0
  7. data/lib/fronde/cli/data/gitignore +0 -1
  8. data/lib/fronde/cli/helpers.rb +0 -2
  9. data/lib/fronde/cli/opt_parse.rb +15 -18
  10. data/lib/fronde/cli/throbber.rb +35 -18
  11. data/lib/fronde/cli.rb +4 -3
  12. data/lib/fronde/config/data/org-config.el +3 -2
  13. data/lib/fronde/config/data/ox-fronde.el +91 -46
  14. data/lib/fronde/config/data/themes/umaneti/css/htmlize.css +364 -0
  15. data/lib/fronde/config/data/themes/umaneti/css/style.css +250 -0
  16. data/lib/fronde/config/data/themes/umaneti/img/bottom.png +0 -0
  17. data/lib/fronde/config/data/themes/umaneti/img/content.png +0 -0
  18. data/lib/fronde/config/data/themes/umaneti/img/tic.png +0 -0
  19. data/lib/fronde/config/data/themes/umaneti/img/top.png +0 -0
  20. data/lib/fronde/config/helpers.rb +1 -19
  21. data/lib/fronde/config/lisp.rb +14 -7
  22. data/lib/fronde/config.rb +47 -31
  23. data/lib/fronde/emacs.rb +23 -9
  24. data/lib/fronde/index/atom_generator.rb +1 -1
  25. data/lib/fronde/index/data/all_tags.org +6 -1
  26. data/lib/fronde/index/data/template.org +8 -4
  27. data/lib/fronde/index/org_generator.rb +10 -6
  28. data/lib/fronde/index.rb +19 -17
  29. data/lib/fronde/org/file.rb +71 -39
  30. data/lib/fronde/org/file_extracter.rb +23 -12
  31. data/lib/fronde/org.rb +14 -12
  32. data/lib/fronde/slug.rb +39 -12
  33. data/lib/fronde/source/gemini.rb +4 -9
  34. data/lib/fronde/source/html.rb +9 -9
  35. data/lib/fronde/source.rb +17 -12
  36. data/lib/fronde/sync/neocities.rb +220 -0
  37. data/lib/fronde/sync/rsync.rb +46 -0
  38. data/lib/fronde/sync.rb +32 -0
  39. data/lib/fronde/templater.rb +35 -51
  40. data/lib/fronde/version.rb +1 -1
  41. data/lib/tasks/cli.rake +45 -13
  42. data/lib/tasks/org.rake +30 -35
  43. data/lib/tasks/site.rake +63 -41
  44. data/lib/tasks/sync.rake +19 -50
  45. data/lib/tasks/tags.rake +2 -2
  46. data/locales/en.yml +143 -81
  47. data/locales/fr.yml +153 -89
  48. metadata +56 -17
  49. data/lib/ext/r18n.rb +0 -17
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 31ed851cf895abccd33ec85ab91459e4310c9716631d096efd89d18fd16bf190
4
- data.tar.gz: 901e11daea515cff4336f05a13a67604a5d73ca9fc020efb8250b34fbdb72450
3
+ metadata.gz: 2d233f108a209e4d5a02633de060293ce6f4981393555ebf5f53f16a25f6d3d0
4
+ data.tar.gz: 9efa6cd46fc4d6d33e98bcee3e7cb1dd43a179736bafb552f6ac3e7a8c5bb8ae
5
5
  SHA512:
6
- metadata.gz: 1190105b49652d3bf177602a9ca37906f9a4659416f821734b17b5a49269825726019a6b69ad47b312937d75b362e658b93026003ffc42cd92859b601c9c8e96
7
- data.tar.gz: 4e34d65345c82cc39237521c2e79365bbe4c23572fa4c4fa7d65e2d5aa7119d095a2956ec569e03c6cb459e7f1f37fe933aac3d2b0fdcefafb69f1cea8ef695b
6
+ metadata.gz: a1c7f18af62f3fbd02be2f025c7d6305a7ea1c3751a35490eee4402de3a4aebf11c211cc3efcc4d57d0b82e99807a439ef920eb67182f0f8313905b20d89fd15
7
+ data.tar.gz: 315634038a4eb1df1c07f019894a0b86b591649f58068d771811bc0bbb92402cc03f79ada03f716caae0e8219075937d1df63ab3e6453827fadb03763203d4da
data/lib/ext/nil_time.rb CHANGED
@@ -10,12 +10,9 @@ class NilTime
10
10
  ''
11
11
  end
12
12
 
13
- def l18n_short_date_string
14
- ''
15
- end
16
-
17
- def l18n_long_date_string(*)
18
- ''
13
+ %i[l18n_short_date_string l18n_long_date_string
14
+ l18n_long_date_no_year_string].each do |name|
15
+ define_method(name) { '' }
19
16
  end
20
17
 
21
18
  def l18n_short_date_html
data/lib/ext/time.rb CHANGED
@@ -7,7 +7,7 @@ module TimePatch
7
7
  #
8
8
  # @return [String] the localized Time string representation
9
9
  def l18n_short_date_string
10
- R18n.l to_date
10
+ I18n.l to_date
11
11
  end
12
12
 
13
13
  # Format the current Time as a HTML `time` tag showing a short date.
@@ -17,26 +17,19 @@ module TimePatch
17
17
  "<time datetime=\"#{xmlschema}\">#{l18n_short_date_string}</time>"
18
18
  end
19
19
 
20
- def no_time=(value)
21
- @no_time = value
20
+ # Returns the current Time instance as a localized long string.
21
+ #
22
+ # @return [String] the localized Time string representation
23
+ def l18n_long_date_string
24
+ I18n.l self, format: :long
22
25
  end
23
26
 
24
- # Returns the current Time instance as a localized long string.
27
+ # Returns the current Time instance as a localized long string
28
+ # without year.
25
29
  #
26
- # @param with_year [Boolean] wether or not the string must contain the
27
- # year
28
30
  # @return [String] the localized Time string representation
29
- def l18n_long_date_string(with_year: true)
30
- locale = R18n.get.locale
31
- long_fmt = R18n.t.fronde.index.full_date_format(
32
- date: locale.format_date_full(self, year: with_year)
33
- )
34
- unless @no_time
35
- long_fmt = R18n.t.fronde.index.full_date_with_time_format(
36
- date: long_fmt, time: locale.time_format.delete('_').strip
37
- )
38
- end
39
- locale.strftime(self, long_fmt)
31
+ def l18n_long_date_no_year_string
32
+ I18n.l self, format: :long_no_year
40
33
  end
41
34
 
42
35
  # Format the current Time as a HTML `time` tag showing a long date.
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ using TimePatch
4
+
5
+ # A time emulator to keep the fact that the time information was
6
+ # missing, even if it behaves as a Time object for the given date.
7
+ class TimeNoTime < Time
8
+ # Returns the current Time instance as a localized long string
9
+ # without time.
10
+ #
11
+ # @return [String] the localized Time string representation
12
+ def l18n_long_date_string
13
+ I18n.l self, format: :long_no_time
14
+ end
15
+
16
+ # Returns the current Time instance as a localized long string
17
+ # without time nor year.
18
+ #
19
+ # @return [String] the localized Time string representation
20
+ def l18n_long_date_no_year_string
21
+ I18n.l self, format: :long_no_time_no_year
22
+ end
23
+
24
+ def self.parse_no_time(string)
25
+ strptime("#{string} 00:00:00", '%Y-%m-%d %H:%M:%S')
26
+ end
27
+ end
@@ -27,13 +27,13 @@ module Fronde
27
27
  init_rake
28
28
  @rake.options.build_all = true
29
29
  @rake['org:upgrade'].invoke
30
- 0
30
+ true
31
31
  end
32
32
 
33
33
  def fronde_build
34
34
  @rake.options.build_all = true
35
35
  @rake['site:build'].invoke @options[:force]
36
- 0
36
+ true
37
37
  end
38
38
 
39
39
  def fronde_preview
@@ -43,7 +43,7 @@ module Fronde
43
43
  Helpers.launch_app_for_uri "http://127.0.0.1:#{port}/"
44
44
  end
45
45
  @rake['site:preview'].invoke
46
- 0
46
+ true
47
47
  end
48
48
 
49
49
  def fronde_open
@@ -58,12 +58,12 @@ module Fronde
58
58
  cmd << '+6'
59
59
  end
60
60
  cmd << file_path
61
- (system(*cmd) && 0) || 1
61
+ system(*cmd)
62
62
  end
63
63
 
64
64
  def fronde_publish
65
65
  @rake['sync:push'].invoke
66
- 0
66
+ true
67
67
  end
68
68
 
69
69
  def fronde_help
@@ -71,22 +71,26 @@ module Fronde
71
71
  @command = @argv.shift || 'basic' if @command == 'help'
72
72
  cmd_opt = OptParse.command_options(@command)
73
73
  label = cmd_opt[:label] || @command
74
- warn format("%<label>s\n\n", label: R18n.t.fronde.bin.usage(label))
74
+ output = [format_label(I18n.t('fronde.bin.usage', label:))]
75
75
  cmd = cmd_opt[:name] || @command
76
- if R18n.t.fronde.bin.commands[cmd].translated?
77
- warn format("%<label>s\n\n", label: R18n.t.fronde.bin.commands[cmd])
78
- end
79
- body = OptParse.help_command_body(cmd)
80
- warn body unless body == ''
81
- 0
76
+ output << format_label(I18n.t("fronde.bin.commands.#{cmd}"))
77
+ output << OptParse.help_command_body(cmd)
78
+ puts output.join
79
+ true
82
80
  end
83
81
 
84
82
  private
85
83
 
84
+ def format_label(label)
85
+ return '' if label == '' || label.start_with?('Translation missing:')
86
+
87
+ format("%<label>s\n\n", label:)
88
+ end
89
+
86
90
  def file_name_from_title
87
- title = @options[:title] || R18n.t.fronde.bin.options.default_title
91
+ title = @options[:title] || I18n.t('fronde.bin.options.default_title')
88
92
  # No title, nor a reliable file_path? Better abort
89
- raise R18n.t.fronde.error.bin.no_file if title == ''
93
+ raise I18n.t('fronde.error.bin.no_file') if title == ''
90
94
 
91
95
  "#{Fronde::Slug.slug(title)}.org"
92
96
  end
@@ -0,0 +1,20 @@
1
+ function __fronde_main_commands
2
+ echo {{ comcomp }}
3
+ end
4
+
5
+ function __fronde_no_command_yet
6
+ set -f cmd (__fish_print_cmd_args_without_options)
7
+ {%- for com in commands %}
8
+ {% unless forloop.first %}and {% endunless %}not contains {{ com }} $cmd
9
+ {%- endfor %}
10
+ end
11
+
12
+ complete -c fronde -e
13
+ complete -c fronde -f
14
+ complete -c fronde -x -n '__fronde_no_command_yet' -a '(__fronde_main_commands)'
15
+ complete -c fronde -n 'contains help (__fish_print_cmd_args_without_options)' -a '{{ commands | join ' ' }}'
16
+ complete -c fronde -n 'contains new (__fish_print_cmd_args_without_options)' -F
17
+ complete -c fronde -n 'contains open (__fish_print_cmd_args_without_options)' -F
18
+ {%- for compopt in details %}
19
+ complete -c fronde{% unless compopt.command == 'basic' %} -n 'contains {{ compopt.command }} (__fish_print_cmd_args_without_options)'{% endunless %} -s {{ compopt.short_no_dash }} -l {{ compopt.long_no_dash }}{% if compopt.keyword %} -r{% endif %}{% if compopt.choices %} -a '{{ compopt.choices | join ' ' }}'{% endif %} -d {% if compopt.help %}'{{ compopt.help }}'{% else %}{{ compopt.long_no_dash | capitalize }}{% endif %}
20
+ {%- endfor %}
@@ -1,4 +1,3 @@
1
- .dir-locals.el
2
1
  .ruby-version
3
2
  Rakefile
4
3
  lib/
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'uri'
4
- require 'net/http'
5
3
  require 'fileutils'
6
4
 
7
5
  module Fronde
@@ -10,13 +10,13 @@ module Fronde
10
10
  '-a' => { long: 'author' },
11
11
  '-f' => { long: 'force', boolean: true },
12
12
  '-h' => { long: 'help', boolean: true, method: :on_tail,
13
- help: R18n.t.fronde.bin.options.help },
13
+ help: I18n.t('fronde.bin.options.help') },
14
14
  '-l' => { long: 'lang', keyword: 'LOCALE' },
15
15
  '-o' => { long: 'output', keyword: 'FORMAT', choices: %w[gemini html] },
16
16
  '-t' => { long: 'title' },
17
17
  '-v' => { long: 'verbose', boolean: true, method: :on_tail },
18
18
  '-V' => { long: 'version', boolean: true, method: :on_tail,
19
- help: R18n.t.fronde.bin.options.version }
19
+ help: I18n.t('fronde.bin.options.version') }
20
20
  }.freeze
21
21
 
22
22
  # TODO: jekyll new [path] / jekyll build / jekyll clean / jekyll serve
@@ -28,13 +28,13 @@ module Fronde
28
28
  FRONDE_COMMANDS = {
29
29
  'new' => { opts: ['-a', '-l', '-o', '-t', '-v'], label: 'new <path>' },
30
30
  'init' => { alias: 'new' },
31
- 'update' => {},
31
+ 'update' => { opts: ['-v'] },
32
32
  'config' => { alias: 'update' },
33
33
  'preview' => {},
34
- 'open' => { opts: ['-a', '-l', '-t', '-v'], label: 'open <path>' },
34
+ 'open' => { opts: ['-a', '-l', '-t'], label: 'open <path>' },
35
35
  'edit' => { alias: 'open' },
36
- 'build' => { opts: ['-f'] },
37
- 'publish' => {},
36
+ 'build' => { opts: ['-f', '-v'] },
37
+ 'publish' => { opts: ['-v'] },
38
38
  'help' => {},
39
39
  'basic' => { opts: ['-h', '-V'], label: '<command>' }
40
40
  }.freeze
@@ -59,11 +59,10 @@ module Fronde
59
59
  config = [short, long]
60
60
  else
61
61
  key = opt[:keyword] || opt[:long].upcase
62
- config = [short, format('%<long>s %<key>s', long: long, key: key)]
62
+ config = [short, format('%<long>s %<key>s', long:, key:)]
63
63
  end
64
- config << opt[:choices] if opt[:choices]
65
- config << opt[:help] if opt[:help]
66
- config
64
+ config.push opt[:choices], opt[:help]
65
+ config.compact
67
66
  end
68
67
 
69
68
  # Returns the ~fronde~ help summary for a given command.
@@ -76,12 +75,10 @@ module Fronde
76
75
  short, long = decorate_option(k)
77
76
  opt = FRONDE_OPTIONS[k]
78
77
  label = [short, long].join(', ')
79
- line = [format(' %<opt>s', opt: label).ljust(30)]
80
- help = opt[:help]
81
- line << help if help
78
+ line = [format(' %<opt>s', opt: label).ljust(30), opt[:help]]
82
79
  choices = opt[:choices]
83
80
  line << "(#{choices.join(', ')})" if choices
84
- line.join(' ')
81
+ line.compact.join(' ')
85
82
  end.join("\n")
86
83
  end
87
84
 
@@ -89,9 +86,9 @@ module Fronde
89
86
  command_opts_doc = summarize_command(command)
90
87
  return '' if command_opts_doc == ''
91
88
 
92
- body = [R18n.t.fronde.bin.options.cmd_title, command_opts_doc]
89
+ body = [I18n.t('fronde.bin.options.cmd_title'), command_opts_doc]
93
90
  if command == 'basic'
94
- body += ['', R18n.t.fronde.bin.commands.cmd_title, list_commands]
91
+ body += ['', I18n.t('fronde.bin.commands.cmd_title'), list_commands]
95
92
  end
96
93
  body.join("\n")
97
94
  end
@@ -105,9 +102,9 @@ module Fronde
105
102
 
106
103
  line = [' ', cmd.ljust(10)]
107
104
  if opt.has_key? :alias
108
- line << R18n.t.fronde.bin.commands.alias(opt[:alias])
105
+ line << I18n.t('fronde.bin.commands.alias', alias: opt[:alias])
109
106
  else
110
- line << R18n.t.fronde.bin.commands[cmd]
107
+ line << I18n.t("fronde.bin.commands.#{cmd}")
111
108
  end
112
109
  line.join(' ')
113
110
  end.join("\n")
@@ -21,6 +21,7 @@ module Fronde
21
21
 
22
22
  def initialize(thread, message)
23
23
  @frames = select_frames
24
+ @term_width = terminal_width
24
25
  @thread = thread
25
26
  @thread.abort_on_exception = false
26
27
  @thread.report_on_exception = false
@@ -28,23 +29,17 @@ module Fronde
28
29
  end
29
30
 
30
31
  def run
31
- term_width = terminal_width
32
- frames_len = @frames.length
33
- current = 0
34
- while @thread.alive?
35
- sleep 0.1
36
- frame = @frames[current % frames_len]
37
- message = "#{@message} #{frame}"
38
- print "#{message.ljust(term_width)}\r"
39
- current += 1
40
- end
41
- @thread.join # Ensure any inner exception is re-raised
32
+ thread_loop
42
33
  rescue RuntimeError => e
43
34
  show_error
44
35
  raise e
36
+ # :nocov: not sure how to emulate a Ctrl+c in rspec
37
+ rescue Interrupt => e
38
+ show_message Rainbow(I18n.t('fronde.bin.interrupted')).red, "\n"
39
+ raise e
40
+ # :nocov:
45
41
  else
46
- done = Rainbow(R18n.t.fronde.bin.done).green
47
- puts "#{@message} #{done}".ljust(term_width)
42
+ show_message Rainbow(I18n.t('fronde.bin.done')).green, "\n"
48
43
  end
49
44
 
50
45
  class << self
@@ -61,15 +56,32 @@ module Fronde
61
56
  #
62
57
  # @param thread [Thread] the long-running operation to decorate
63
58
  # @param message [String] the message to display before the throbber
59
+ # @param verbose [Boolean] whether the decoration should be shown
60
+ # or skipped
64
61
  # @return [void]
65
- def run(thread, message)
66
- throbber = new(thread, message)
67
- throbber.run
62
+ def run(thread, message, verbose)
63
+ if verbose
64
+ thread.join
65
+ else
66
+ throbber = new(thread, message)
67
+ throbber.run
68
+ end
68
69
  end
69
70
  end
70
71
 
71
72
  private
72
73
 
74
+ def thread_loop
75
+ frames_len = @frames.length
76
+ current = 0
77
+ while @thread.alive?
78
+ sleep 0.1
79
+ show_message @frames[current % frames_len]
80
+ current += 1
81
+ end
82
+ @thread.join # Ensure any inner exception is re-raised
83
+ end
84
+
73
85
  def terminal_width
74
86
  # Not a tty. Docker?
75
87
  return 0 unless system('test -t 0')
@@ -77,13 +89,18 @@ module Fronde
77
89
  `stty size`.strip.split[1].to_i - 1
78
90
  end
79
91
 
92
+ def show_message(suffix, end_of_line = "\r")
93
+ message = "#{@message} #{suffix}".ljust(@term_width)
94
+ print "#{message}#{end_of_line}"
95
+ end
96
+
80
97
  def show_error
81
98
  warn(
82
99
  format(
83
100
  "%<message>s %<label>s\n%<explanation>s",
84
101
  message: @message,
85
- label: Rainbow(R18n.t.fronde.error.bin.label).bold.red,
86
- explanation: Rainbow(R18n.t.fronde.error.bin.explanation).bold
102
+ label: Rainbow(I18n.t('fronde.error.bin.label')).bold.red,
103
+ explanation: Rainbow(I18n.t('fronde.error.bin.explanation')).bold
87
104
  )
88
105
  )
89
106
  end
data/lib/fronde/cli.rb CHANGED
@@ -21,12 +21,13 @@ module Fronde
21
21
 
22
22
  if help_param_given?
23
23
  return 2 if @options[:recover_from_error]
24
- return 0
24
+
25
+ return true
25
26
  end
26
27
 
27
28
  init_rake if %w[build preview publish].include?(@command)
28
29
 
29
- method = "fronde_#{@command}".to_sym
30
+ method = :"fronde_#{@command}"
30
31
  return 2 if method_unknown?(method)
31
32
 
32
33
  send method
@@ -50,7 +51,7 @@ module Fronde
50
51
  def method_unknown?(method)
51
52
  return false if respond_to?(method)
52
53
 
53
- warn R18n.t.fronde.error.bin.no_command
54
+ warn I18n.t('fronde.error.bin.no_command')
54
55
  fronde_help
55
56
  true
56
57
  end
@@ -4,8 +4,9 @@
4
4
  (load-file (expand-file-name "htmlize.el" "{{ work_dir }}/lib"))
5
5
 
6
6
  ;; Current project options
7
- (setq fronde/version "{{ version }}"
8
- fronde/current-work-dir "{{ work_dir }}"
7
+ (setq fronde-version "{{ version }}"
8
+ fronde-current-work-dir "{{ work_dir }}"
9
+ fronde-domain "{{ domain }}"
9
10
  user-mail-address "{{ author.email }}"
10
11
  user-full-name "{{ author.name }}"
11
12
  org-html-metadata-timestamp-format "{{ long_date_fmt }}"
@@ -34,87 +34,132 @@
34
34
 
35
35
  ;;; Function Declarations
36
36
 
37
- (defvar fronde/version ""
38
- "Version of the current fronde installation")
37
+ (defvar fronde-version ""
38
+ "Version of the current fronde installation.")
39
39
 
40
- (defvar fronde/current-work-dir nil
40
+ (defvar fronde-current-work-dir nil
41
41
  "Location of the current fronde website base directory.")
42
42
 
43
- (defvar fronde/org-temp-dir nil
44
- "Location of the local Org temporary directory (where to place
45
- org timestamps and id locations).")
46
-
47
- (defun fronde/org-html-format-spec (upstream info)
48
- "Return format specification for preamble and postamble.
43
+ (defvar fronde-domain ""
44
+ "Target domain with scheme of the current fronde installation.")
45
+
46
+ (defvar fronde-org-temp-dir nil
47
+ "Location of the local Org temporary directory.
48
+ This is where to place org timestamps and id locations.")
49
+
50
+ (defvar fronde--keywords-slugs-alist nil
51
+ "A list associating each keywords to its related slug.
52
+
53
+ Can be hydrated with `fronde--build-keywords-list'.")
54
+
55
+ (defun fronde--build-keywords-list ()
56
+ (let ((keywords-file (format "%s/keywords" fronde-org-temp-dir))
57
+ keywords-slugs)
58
+ (when (file-readable-p keywords-file)
59
+ (let ((content (with-temp-buffer
60
+ (insert-file-contents keywords-file)
61
+ (string-trim-right (buffer-string)))))
62
+ (mapcar
63
+ (lambda (line)
64
+ (push (split-string line "\x1f") keywords-slugs))
65
+ (split-string content "\x1e"))))
66
+ keywords-slugs))
67
+
68
+ (defun fronde--format-rich-keywords (info function)
69
+ "Extract keywords from INFO and apply FUNCTION on them.
70
+ FUNCTION is expected to format each keyword for a rich display for the
71
+ current export backend. FUNCTION must receive 3 arguments: the current
72
+ KEYWORD, its related SLUG and the current project BASE-URI."
73
+ (let ((base-uri (plist-get info :fronde-base-uri)))
74
+ (mapcar
75
+ (lambda (k)
76
+ (let ((slug (cadr (assoc k fronde--keywords-slugs-alist))))
77
+ (funcall function k slug base-uri)))
78
+ (split-string
79
+ (org-export-data (plist-get info :keywords) info)
80
+ ",+ *"))))
81
+
82
+ (defun fronde--org-html-format-spec (upstream info)
83
+ "Advise UPSTREAM to return format specification for preamble and postamble.
49
84
  INFO is a plist used as a communication channel."
50
85
  (let ((output (funcall upstream info)))
51
86
  (push `(?A . ,(format "<span class=\"author\">%s</span>"
52
87
  (org-export-data (plist-get info :author) info)))
53
- output)
88
+ output)
54
89
  (push `(?k . ,(org-export-data (plist-get info :keywords) info)) output)
55
- (push `(?K . ,(format "<ul class=\"keywords-list\">%s</ul>"
56
- (mapconcat
57
- (lambda (k) (format "<li class=\"keyword\">%s</li>" k))
58
- (split-string (or (plist-get info :keywords) "") ",+ *")
59
- "\n")))
60
- output)
90
+ (push `(?K . ,(format "<ul class=\"keywords-list\">\n%s</ul>"
91
+ (apply #'concat
92
+ (fronde--format-rich-keywords
93
+ info
94
+ (lambda (k slug base-uri)
95
+ (format "<li class=\"keyword\"><a href=\"%stags/%s.html\">%s</a></li>\n"
96
+ base-uri slug k))))))
97
+ output)
61
98
  (push `(?l . ,(org-export-data (plist-get info :language) info)) output)
62
- (push `(?n . ,(format "Fronde %s" fronde/version)) output)
63
- (push `(?N . ,(format "<a href=\"https://etienne.depar.is/fronde/\">Fronde</a> %s" fronde/version)) output)
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)
64
101
  (push `(?x . ,(org-export-data (plist-get info :description) info)) output)
65
102
  (push `(?X . ,(format "<p>%s</p>"
66
103
  (org-export-data (plist-get info :description) info)))
67
- output)))
104
+ output)))
68
105
 
69
- (defun fronde/org-gmi-format-spec (upstream info)
70
- "Return format specification for gemini postamble.
106
+ (defun fronde--org-gmi-format-spec (upstream info)
107
+ "Advise UPSTREAM to return format specification for gemini postamble.
71
108
  INFO is a plist used as a communication channel."
72
109
  (let ((output (funcall upstream info)))
73
- (push `(?n . ,(format "Fronde %s" fronde/version)) output)))
74
-
75
- (defun fronde/org-i18n-export (link description format)
76
- "Export a i18n link"
77
- (let* ((splitted-link (split-string link "|"))
110
+ (push `(?K . ,(org-gmi--build-links-list
111
+ (fronde--format-rich-keywords
112
+ info
113
+ (lambda (k slug base-uri)
114
+ (list (format "%stags/%s.gmi" base-uri slug)
115
+ (format "🏷️ %s" k))))))
116
+ output)
117
+ (push `(?n . ,(format "Fronde %s" fronde-version)) output)))
118
+
119
+ (defun fronde--org-i18n-export (link description backend)
120
+ "Export the given i18n LINK with its DESCRIPTION for the current BACKEND."
121
+ (let* ((splitted-link (split-string link "::"))
78
122
  (path (car splitted-link))
79
123
  (desc (or description path))
80
124
  (lang (cadr splitted-link)))
81
- (pcase format
125
+ (pcase backend
82
126
  (`html (if lang
83
127
  (format "<a href=\"%s\" hreflang=\"%s\">%s</a>"
84
128
  path lang desc)
85
129
  (format "<a href=\"%s\">%s</a>" path desc)))
86
- (`latex (format "\\href{%s}{%s}" path desc))
87
- (_ (format "%s (%s)" desc path)))))
130
+ (_ nil))))
88
131
 
89
- (defun fronde/org-i18n-follow (link)
90
- "Visit a i18n link"
91
- (browse-url (car (split-string link "|"))))
132
+ (defun fronde--org-i18n-follow (link)
133
+ "Visit the given i18n LINK."
134
+ (browse-url (car (split-string link "::"))))
92
135
 
93
136
  (org-link-set-parameters "i18n"
94
- :export #'fronde/org-i18n-export
95
- :follow #'fronde/org-i18n-follow)
137
+ :export #'fronde--org-i18n-export
138
+ :follow #'fronde--org-i18n-follow)
96
139
 
97
140
 
98
141
  ;;; Set configuration options
99
142
 
100
- (setq fronde/org-temp-dir (expand-file-name "var/tmp" fronde/current-work-dir)
101
- org-publish-timestamp-directory (expand-file-name "timestamps/" fronde/org-temp-dir)
102
- org-id-locations-file (expand-file-name "id-locations.el" fronde/org-temp-dir)
143
+ (setq fronde-org-temp-dir (expand-file-name "var/tmp" fronde-current-work-dir)
144
+ fronde--keywords-slugs-alist (fronde--build-keywords-list)
145
+ org-publish-timestamp-directory (expand-file-name "timestamps/" fronde-org-temp-dir)
146
+ org-id-locations-file (expand-file-name "id-locations.el" fronde-org-temp-dir)
103
147
  make-backup-files nil
104
- enable-local-variables :all
105
- org-confirm-babel-evaluate nil
148
+ enable-dir-local-variables nil
149
+ enable-local-variables t ;; enforce default
150
+ org-confirm-babel-evaluate t ;; enforce default
106
151
  org-export-with-broken-links t
107
152
  org-html-doctype "html5"
108
153
  org-html-html5-fancy t
109
154
  org-html-htmlize-output-type 'css
110
155
  org-html-text-markup-alist '((bold . "<strong>%s</strong>")
111
- (code . "<code>%s</code>")
112
- (italic . "<em>%s</em>")
113
- (strike-through . "<del>%s</del>")
114
- (underline . "<span class=\"underline\">%s</span>")
115
- (verbatim . "<code>%s</code>")))
116
- (advice-add 'org-html-format-spec :around #'fronde/org-html-format-spec)
117
- (advice-add 'org-gmi--format-spec :around #'fronde/org-gmi-format-spec)
156
+ (code . "<code>%s</code>")
157
+ (italic . "<em>%s</em>")
158
+ (strike-through . "<del>%s</del>")
159
+ (underline . "<span class=\"underline\">%s</span>")
160
+ (verbatim . "<code>%s</code>")))
161
+ (advice-add 'org-html-format-spec :around #'fronde--org-html-format-spec)
162
+ (advice-add 'org-gmi--format-spec :around #'fronde--org-gmi-format-spec)
118
163
 
119
164
  (provide 'ox-fronde)
120
165