fronde 0.4.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
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