fronde 0.5.0 → 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
data/lib/fronde/index.rb CHANGED
@@ -8,7 +8,7 @@ module Fronde
8
8
  # Generates website indexes and atom feeds for all the org documents
9
9
  # keywords.
10
10
  class Index
11
- attr_reader :date
11
+ attr_reader :date, :project
12
12
 
13
13
  def initialize(project)
14
14
  @project = project
@@ -31,7 +31,8 @@ module Fronde
31
31
  def sort_by(kind)
32
32
  accepted_values = %i[name weight]
33
33
  unless accepted_values.include?(kind)
34
- error_msg = R18n.t.fronde.error.index.wrong_sort_kind(
34
+ error_msg = I18n.t(
35
+ 'fronde.error.index.wrong_sort_kind',
35
36
  kind: kind, accepted_values: accepted_values.inspect
36
37
  )
37
38
  raise ArgumentError, error_msg
@@ -43,6 +44,10 @@ module Fronde
43
44
  # and avoid to scroll to find the beginning of the list.
44
45
  end
45
46
 
47
+ def emacs_keywords
48
+ @tags_names.map { |slug, title| "#{title}\x1f#{slug}" }.join("\x1e")
49
+ end
50
+
46
51
  class << self
47
52
  def all_blog_index(&block)
48
53
  all_blogs = CONFIG.sources.filter_map do |project|
@@ -91,7 +96,7 @@ module Fronde
91
96
  all_keys = all_tags
92
97
  {
93
98
  by_name: all_keys.sort,
94
- by_weight: all_keys.sort_by { @index[_1].length }.reverse
99
+ by_weight: all_keys.sort_by { [-@index[_1].length, _1] }
95
100
  }
96
101
  end
97
102
  end
@@ -109,6 +109,21 @@ module Fronde
109
109
  @data[:date].strftime('%Y%m%d%H%M%S')
110
110
  end
111
111
 
112
+ # Returns the path to the published version of this document.
113
+ #
114
+ # By default, this method returns the relative path to the published
115
+ # file. If the ~absolute~ argument is true, it will return the absolute
116
+ # path to the published file.
117
+ #
118
+ # @param absolute [Boolean] whether to display absolute or relative
119
+ # published file path (default false)
120
+ # @return [String] the document key
121
+ def pub_file(absolute: false)
122
+ return @data[:pub_file] unless absolute
123
+
124
+ "#{@project['folder']}#{@data[:pub_file]}"
125
+ end
126
+
112
127
  # Formats given ~string~ with values of the current Org::File.
113
128
  #
114
129
  # This method expects to find percent-tags in the given ~string~
@@ -151,6 +166,7 @@ module Fronde
151
166
  # org_file.format("Article written by %a the %d")
152
167
  # => "Article written by Alice Smith the Wednesday 3rd July"
153
168
  #
169
+ # @param string [String] the template text to edit
154
170
  # @return [String] the given ~string~ after replacement occurs
155
171
  # rubocop:disable Layout/LineLength
156
172
  def format(string)
@@ -159,13 +175,18 @@ module Fronde
159
175
  # %a (author), %c (creator), %C (input-file), %d (date),
160
176
  # %e (email), %s (subtitle), %t (title), %T (timestamp),
161
177
  # %v (html validation link)
178
+ localized_dates = I18n.with_locale(@data[:lang]) do
179
+ { short: @data[:date].l18n_short_date_string,
180
+ short_html: @data[:date].l18n_short_date_html,
181
+ long_html: @data[:date].l18n_long_date_html }
182
+ end
162
183
  string.gsub('%a', @data[:author])
163
184
  .gsub('%A', "<span class=\"author\">#{@data[:author]}</span>")
164
- .gsub('%d', @data[:date].l18n_short_date_html)
165
- .gsub('%D', @data[:date].l18n_long_date_html)
185
+ .gsub('%d', localized_dates[:short_html])
186
+ .gsub('%D', localized_dates[:long_html])
166
187
  .gsub('%F', project_data['atom_feed'] || '')
167
188
  .gsub('%h', project_data['domain'] || '')
168
- .gsub('%i', @data[:date].l18n_short_date_string)
189
+ .gsub('%i', localized_dates[:short])
169
190
  .gsub('%I', @data[:date].xmlschema)
170
191
  .gsub('%k', @data[:keywords].join(', '))
171
192
  .gsub('%K', keywords_to_html)
@@ -191,18 +212,17 @@ module Fronde
191
212
  def write
192
213
  if ::File.directory? @file
193
214
  if @data[:title] == ''
194
- raise R18n.t.fronde.error.org_file.no_file_or_title
215
+ raise I18n.t('fronde.error.org_file.no_file_or_title')
195
216
  end
196
217
 
197
218
  @file = ::File.join @file, "#{Slug.slug(@data[:title])}.org"
198
219
  else
199
- file_dir = ::File.dirname @file
200
- FileUtils.mkdir_p file_dir
220
+ FileUtils.mkdir_p ::File.dirname(@file)
201
221
  end
202
222
  ::File.write @file, @data[:content]
203
223
  end
204
224
 
205
- def method_missing(method_name, *args, &block)
225
+ def method_missing(method_name, *args, &)
206
226
  reader_method = method_name.to_s.delete_suffix('=').to_sym
207
227
  if @data.has_key? reader_method
208
228
  return @data[reader_method] if reader_method == method_name
@@ -222,11 +242,13 @@ module Fronde
222
242
  end
223
243
 
224
244
  def to_h
225
- fields = %w[author excerpt keywords timekey title url]
245
+ fields = %w[author excerpt keywords lang timekey title url]
226
246
  data = fields.to_h { |key| [key, send(key)] }
227
247
  data['published_body'] = extract_published_body
228
248
  pub_date = @data[:date]
229
- data['published'] = pub_date.l18n_long_date_string(with_year: false)
249
+ data['published'] = I18n.with_locale(@data[:lang]) do
250
+ pub_date.l18n_long_date_no_year_string
251
+ end
230
252
  data['published_gemini_index'] = pub_date.strftime('%Y-%m-%d')
231
253
  data['published_xml'] = pub_date.xmlschema
232
254
  data['updated_xml'] = @data[:updated]&.xmlschema
@@ -244,13 +266,11 @@ module Fronde
244
266
  return source if source
245
267
 
246
268
  short_file = @file.sub(/^#{Dir.pwd}/, '.')
247
- warn R18n.t.fronde.error.org_file.no_project(file: short_file)
269
+ warn I18n.t('fronde.error.org_file.no_project', file: short_file)
248
270
  end
249
271
 
250
272
  def find_source_for_org_file
251
- Fronde::CONFIG.sources.find do |project|
252
- project.source_for? @file
253
- end
273
+ Fronde::CONFIG.sources.find { _1.source_for? @file }
254
274
  end
255
275
 
256
276
  def find_source_for_publication_file
@@ -20,11 +20,19 @@ module Fronde
20
20
  end
21
21
  return unless @project
22
22
 
23
+ warn_if_dangerous_code_block
23
24
  @data[:updated] = ::File.mtime(@file)
24
25
  @data[:pub_file] = @project.target_for @file
25
26
  @data[:url] = Fronde::CONFIG.get('domain') + @data[:pub_file]
26
27
  end
27
28
 
29
+ def warn_if_dangerous_code_block
30
+ code_block_rx = /^#\+begin_src.+:exports (?:results|both).*$/i
31
+ return unless code_block_rx.match?(@data[:content])
32
+
33
+ warn I18n.t('fronde.error.org_file.dangerous_code_block', file: @file)
34
+ end
35
+
28
36
  def extract_date
29
37
  timerx = '([0-9:]{5})(?::([0-9]{2}))?'
30
38
  daterx = /^#\+date: *<([0-9-]{10}) [\w.]+(?: #{timerx})?> *$/i
data/lib/fronde/org.rb CHANGED
@@ -10,7 +10,7 @@ module Fronde
10
10
  class << self
11
11
  def current_version
12
12
  # Do not crash if Org is not yet installed (and thus return nil)
13
- Dir['lib/org-*'].first&.delete_prefix('lib/org-')
13
+ Dir.glob('lib/org-*').first&.delete_prefix('lib/org-')
14
14
  end
15
15
 
16
16
  # Fetch and return the last published version of Org.
@@ -97,8 +97,8 @@ module Fronde
97
97
  FileUtils.mv "org-mode-release_#{version}", target
98
98
  # Fix a weird unknown package version
99
99
  ::File.write("#{target}/mk/version.mk", "ORGVERSION ?= #{version}")
100
- system(*make_org_cmd(target, 'compile', verbose: verbose))
101
- system(*make_org_cmd(target, 'autoloads', verbose: verbose))
100
+ system(*make_org_cmd(target, 'compile', verbose:))
101
+ system(*make_org_cmd(target, 'autoloads', verbose:))
102
102
  end
103
103
  end
104
104
  end
@@ -8,9 +8,9 @@ module Fronde
8
8
  def org_default_postamble
9
9
  format(
10
10
  "📅 %<date>s\n📝 %<author>s %<creator>s",
11
- author: R18n.t.fronde.org.postamble.written_by,
12
- creator: R18n.t.fronde.org.postamble.with_emacs,
13
- date: R18n.t.fronde.org.postamble.last_modification
11
+ author: I18n.t('fronde.org.postamble.written_by'),
12
+ creator: I18n.t('fronde.org.postamble.with_emacs'),
13
+ date: I18n.t('fronde.org.postamble.last_modification')
14
14
  )
15
15
  end
16
16
  end
@@ -20,7 +20,7 @@ module Fronde
20
20
  def fill_in_specific_config
21
21
  @config.merge!(
22
22
  'type' => 'gemini', 'ext' => '.gmi', 'mime_type' => 'text/gemini',
23
- 'folder' => CONFIG.get('gemini_public_folder')
23
+ 'folder' => File.expand_path(CONFIG.get('gemini_public_folder'))
24
24
  )
25
25
  end
26
26
 
@@ -13,9 +13,9 @@ module Fronde
13
13
  class << self
14
14
  def org_default_postamble
15
15
  <<~POSTAMBLE
16
- <p><span class="author">#{R18n.t.fronde.org.postamble.written_by}</span>
17
- #{R18n.t.fronde.org.postamble.with_emacs_html}</p>
18
- <p class="date">#{R18n.t.fronde.org.postamble.last_modification}</p>
16
+ <p><span class="author">#{I18n.t('fronde.org.postamble.written_by')}</span>
17
+ #{I18n.t('fronde.org.postamble.with_emacs_html')}</p>
18
+ <p class="date">#{I18n.t('fronde.org.postamble.last_modification')}</p>
19
19
  <p class="validation">%v</p>
20
20
  POSTAMBLE
21
21
  end
@@ -26,7 +26,7 @@ module Fronde
26
26
  def fill_in_specific_config
27
27
  @config.merge!(
28
28
  'type' => 'html', 'ext' => '.html', 'mime_type' => 'text/html',
29
- 'folder' => CONFIG.get('html_public_folder')
29
+ 'folder' => File.expand_path(CONFIG.get('html_public_folder'))
30
30
  )
31
31
  end
32
32
 
data/lib/fronde/source.rb CHANGED
@@ -58,11 +58,11 @@ module Fronde
58
58
  def source_for(file_name)
59
59
  relative_file_path = file_name.delete_prefix "#{publication_path}/"
60
60
  # file_name does not begin with source path.
61
- return nil if relative_file_path == file_name
61
+ return if relative_file_path == file_name
62
62
 
63
63
  # Looks like a file at a deeper level, but current source is not
64
64
  # recursive.
65
- return nil if relative_file_path.include?('/') && !recursive?
65
+ return if relative_file_path.include?('/') && !recursive?
66
66
 
67
67
  # Looks like a match. But does a source file for this one actually
68
68
  # exists?
@@ -70,7 +70,7 @@ module Fronde
70
70
  /#{@config['ext']}\z/, '.org'
71
71
  )
72
72
  source_path = File.join(@config['path'], relative_source_path)
73
- return nil unless File.file?(source_path)
73
+ return unless File.file?(source_path)
74
74
 
75
75
  source_path
76
76
  end
@@ -111,7 +111,7 @@ module Fronde
111
111
  def publication_path
112
112
  return @config['publication_path'] if @config['publication_path']
113
113
 
114
- publish_in = [File.expand_path(@config['folder']), @config['target']]
114
+ publish_in = [@config['folder'], @config['target']]
115
115
  @config['publication_path'] = publish_in.join('/').delete_suffix('/')
116
116
  end
117
117
 
@@ -35,7 +35,7 @@ module Fronde
35
35
 
36
36
  def local_list
37
37
  Dir.chdir(@public_folder) do
38
- Dir['**/*'].map { |file| neocities_stat(file) }
38
+ Dir.glob('**/*').map { |file| neocities_stat(file) }
39
39
  end
40
40
  end
41
41
 
@@ -52,19 +52,19 @@ module Fronde
52
52
  file_list = remote_list
53
53
  finish
54
54
  orphans = select_orphans(file_list, local_list) do |path|
55
- warn "deleting #{path}" if @verbose
55
+ puts I18n.t('fronde.neocities.deleting', path:) if @verbose
56
56
 
57
57
  "#{@public_folder}/#{path}"
58
58
  end
59
59
  File.unlink(*orphans) unless test
60
- download_all file_list, test: test
60
+ download_all(file_list, test:)
61
61
  nil # Mute this method
62
62
  end
63
63
 
64
64
  def push(test: false)
65
65
  file_list = local_list
66
- remove_remote_orphans file_list, test: test
67
- upload_all file_list, test: test
66
+ remove_remote_orphans(file_list, test:)
67
+ upload_all(file_list, test:)
68
68
  finish
69
69
  end
70
70
 
@@ -84,10 +84,10 @@ module Fronde
84
84
  data
85
85
  end
86
86
 
87
- def select_orphans(to_apply, current_list, &block)
87
+ def select_orphans(to_apply, current_list, &)
88
88
  paths_to_apply = to_apply.map { _1['path'] }
89
89
  current_paths = current_list.map { _1['path'] }
90
- (current_paths - paths_to_apply).filter_map(&block)
90
+ (current_paths - paths_to_apply).filter_map(&)
91
91
  end
92
92
 
93
93
  def remove_remote_orphans(file_list, test: false)
@@ -98,7 +98,7 @@ module Fronde
98
98
  # the index.html file to be removed.
99
99
  next if PROTECTED_FILES.include? path
100
100
 
101
- warn "deleting #{path}" if @verbose
101
+ puts I18n.t('fronde.neocities.deleting', path:) if @verbose
102
102
  path
103
103
  end
104
104
  request.form_data = { 'filenames[]' => orphan_paths }
@@ -114,7 +114,7 @@ module Fronde
114
114
  file_list.each do |file_data|
115
115
  path = file_data['path']
116
116
  file_data['uri'] = "https://#{publish_domain}/#{path}"
117
- download_file http, file_data, test: test
117
+ download_file http, file_data, test:
118
118
  end
119
119
  end
120
120
  end
@@ -123,12 +123,12 @@ module Fronde
123
123
  def download_file(http, file_data, test: false)
124
124
  path = file_data['path']
125
125
  if file_data['is_directory']
126
- warn "#{path}/" if @verbose
126
+ puts "#{path}/" if @verbose
127
127
  FileUtils.mkdir_p path unless test
128
128
  return
129
129
  end
130
130
 
131
- warn path if @verbose
131
+ puts path if @verbose
132
132
 
133
133
  content = fetch_file_content(
134
134
  http, file_data['uri'], file_data['sha1_hash']
@@ -146,7 +146,7 @@ module Fronde
146
146
  check = Digest::SHA1.hexdigest content
147
147
  return content if check == sha1sum
148
148
 
149
- warn "SHA1 hash differ for #{uri}"
149
+ warn I18n.t('fronde.neocities.sha1_differ', uri:)
150
150
  end
151
151
 
152
152
  def save_file(path, content, updated_at)
@@ -163,7 +163,7 @@ module Fronde
163
163
  next if file_data['is_directory']
164
164
 
165
165
  path = file_data['path']
166
- warn path if @verbose
166
+ puts path if @verbose
167
167
  [path, File.new(path)]
168
168
  end
169
169
  end
@@ -13,17 +13,17 @@ module Fronde
13
13
  end
14
14
 
15
15
  def pull(test: false)
16
- run command(test: test) + [@remote_path, @local_path]
16
+ run command(test:) + [@remote_path, @local_path]
17
17
  end
18
18
 
19
19
  def push(test: false)
20
- run command(test: test) + [@local_path, @remote_path]
20
+ run command(test:) + [@local_path, @remote_path]
21
21
  end
22
22
 
23
23
  private
24
24
 
25
25
  def run(cmd)
26
- warn cmd.join(' ') if @verbose
26
+ puts cmd.join(' ') if @verbose
27
27
  # Be precise about Kernel to allow mock in rspec
28
28
  Kernel.system(*cmd)
29
29
  end
data/lib/fronde/sync.rb CHANGED
@@ -25,8 +25,8 @@ module Fronde
25
25
  method, remote_path = extract_method_and_remote type
26
26
  public_folder = Fronde::CONFIG.get("#{type}_public_folder")
27
27
  klass = Kernel.const_get("::Fronde::Sync::#{method.capitalize}")
28
- syncer = klass.new(remote_path, public_folder, verbose: verbose)
29
- Thread.new { syncer.send(direction, test: test) }
28
+ syncer = klass.new(remote_path, public_folder, verbose:)
29
+ Thread.new { syncer.send(direction, test:) }
30
30
  end
31
31
  end
32
32
  end
@@ -5,8 +5,6 @@ require 'digest/md5'
5
5
  require_relative 'org/file'
6
6
 
7
7
  module Fronde
8
- class NoHeadError < ::StandardError; end
9
-
10
8
  # Insert custom part inside generated HTML files.
11
9
  class Templater
12
10
  def initialize(source, dom, config = {})
@@ -19,74 +17,55 @@ module Fronde
19
17
 
20
18
  def apply
21
19
  # Flag the file for this template
22
- head = @dom.xpath('//head').first
23
- raise NoHeadError, self unless head
24
-
25
- head.prepend_child("<!--#{@config['check_line']}-->")
20
+ html = @dom.xpath('//html').first
21
+ html.add_child("<!--#{@config['check_line']}-->\n")
26
22
  content = @org_file.format extract_content
27
23
  # Remove source element if necessary to avoid doubling it during
28
24
  # the insert action
29
25
  @config['source'].unlink if @config.has_key? 'source'
30
26
  # Insert new content
31
- @dom.css(@config['selector']).each do |element|
27
+ @dom.css(@config['selector']).map do |element|
32
28
  insert_new_node_at element, content
33
29
  end
34
30
  end
35
31
 
36
- def in_head?
37
- @dom.xpath('//head').children.any? do |child|
32
+ def applied?
33
+ @dom.xpath('//html').children.any? do |child|
38
34
  next false unless child.comment?
39
35
 
40
36
  child.text == @config['check_line']
41
37
  end
42
38
  end
43
39
 
44
- def valid?(file_name)
40
+ def valid?
45
41
  return false unless @config.has_key?('selector')
46
42
 
47
43
  unless @config.has_key?('content') || @config.has_key?('source')
48
44
  return false
49
45
  end
50
46
 
51
- check_path(file_name)
47
+ check_path
52
48
  end
53
49
 
54
50
  class << self
55
51
  def customize_output(file_name)
56
- source = Fronde::Org::File.new(file_name)
52
+ source = Fronde::Org::File.new file_name
57
53
  # Return if no org file found for this published file
58
- return if source.file.end_with?(file_name)
54
+ return unless source.pub_file
59
55
 
60
- dom = open_dom(file_name)
61
- updated = apply_templates(source, dom, file_name)
62
- write_dom(file_name, dom) if updated
56
+ apply_templates source
63
57
  end
64
58
 
65
- private
66
-
67
- def apply_templates(source, dom, file_name)
68
- Fronde::CONFIG.get('templates', []).map do |config|
59
+ def apply_templates(source)
60
+ public_file = source.pub_file absolute: true
61
+ dom = File.open(public_file, 'r') { Nokogiri::HTML _1 }
62
+ changes = Fronde::CONFIG.get('templates', []).map do |config|
69
63
  template = Fronde::Templater.new(source, dom, config)
70
- next if !template.valid?(file_name) || template.in_head?
64
+ next if !template.valid? || template.applied?
71
65
 
72
66
  template.apply
73
- true
74
- rescue NoHeadError
75
- warn R18n.t.fronde.error.templater.no_head_element(file: file_name)
76
- next
77
- end.any?
78
- end
79
-
80
- def open_dom(file_name)
81
- File.open(file_name, 'r') do |file|
82
- Nokogiri::HTML file
83
- end
84
- end
85
-
86
- def write_dom(file_name, dom)
87
- File.open(file_name, 'w') do |file|
88
- dom.write_to file
89
67
  end
68
+ File.open(public_file, 'w') { dom.write_to _1 } if changes.any?
90
69
  end
91
70
  end
92
71
 
@@ -104,12 +83,11 @@ module Fronde
104
83
  end
105
84
 
106
85
  def warn_no_element(source)
107
- pub_folder = Fronde::CONFIG.get('html_public_folder').sub(
108
- /^#{Dir.pwd}/, '.'
109
- )
86
+ public_file = @org_file.pub_file(absolute: true)
110
87
  warn(
111
- R18n.t.fronde.error.templater.no_element_found(
112
- source: source, file: "#{pub_folder}#{@org_file.pub_file}"
88
+ I18n.t(
89
+ 'fronde.error.templater.no_element_found',
90
+ source: source, file: public_file.sub(/^#{Dir.pwd}/, '.')
113
91
  )
114
92
  )
115
93
  '' # Return empty string
@@ -133,15 +111,14 @@ module Fronde
133
111
  warn_no_element source
134
112
  end
135
113
 
136
- def check_path(file_name)
114
+ def check_path
137
115
  paths = @config['path']
138
116
  return true unless paths
139
117
 
140
118
  paths = [paths] unless paths.is_a? Array
141
119
 
142
- pub_folder = Fronde::CONFIG.get('html_public_folder')
143
120
  paths.any? do |template_path|
144
- File.fnmatch?("#{pub_folder}#{template_path}", file_name)
121
+ File.fnmatch?(template_path, @org_file.pub_file)
145
122
  end
146
123
  end
147
124
  end
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Fronde
4
4
  # @return [String] the version number of the current Fronde release.
5
- VERSION = '0.5.0'
5
+ VERSION = '0.6.1'
6
6
  end
data/lib/tasks/cli.rake CHANGED
@@ -2,6 +2,24 @@
2
2
 
3
3
  require_relative '../fronde/cli/opt_parse'
4
4
 
5
+ def comp_opt_to_liquid(option, command)
6
+ opt_config = Fronde::CLI::OptParse::FRONDE_OPTIONS[option]
7
+ keyword = nil
8
+ unless opt_config[:boolean]
9
+ keyword = opt_config[:keyword] || opt_config[:long].upcase
10
+ end
11
+ {
12
+ 'command' => command,
13
+ 'short' => option,
14
+ 'short_no_dash' => option.delete_prefix('-'),
15
+ 'long' => "--#{opt_config[:long]}",
16
+ 'long_no_dash' => opt_config[:long],
17
+ 'keyword' => keyword,
18
+ 'choices' => opt_config[:choices],
19
+ 'help' => opt_config[:help]
20
+ }
21
+ end
22
+
5
23
  namespace :cli do
6
24
  desc 'Generate an autocomplete file for zsh'
7
25
  task :zsh_complete do
@@ -10,24 +28,38 @@ namespace :cli do
10
28
  data['commands'] = all_commands.filter_map do |command, options|
11
29
  next if options[:alias] || command == 'basic'
12
30
 
13
- opts = (options[:opts] || []).map do |opt|
14
- opt_config = Fronde::CLI::OptParse::FRONDE_OPTIONS[opt]
15
- keyword = nil
16
- unless opt_config[:boolean]
17
- keyword = opt_config[:keyword] || opt_config[:long].upcase
18
- end
19
- { 'short' => opt,
20
- 'long' => "--#{opt_config[:long]}",
21
- 'keyword' => keyword }
22
- end
23
-
24
- translation = R18n.t.fronde.bin.commands[command].tr("'", '’')
31
+ opts = (options[:opts] || []).map { comp_opt_to_liquid(_1, command) }
25
32
  { 'name' => command,
26
- 'translation' => translation,
33
+ 'translation' => I18n.t("fronde.bin.commands.#{command}"),
27
34
  'options' => opts }
28
35
  end
29
36
  source = File.expand_path '../fronde/cli/data/zsh_completion', __dir__
30
37
  template = Liquid::Template.parse(File.read(source))
31
38
  puts template.render(data)
32
39
  end
40
+
41
+ desc 'Generate an autocomplete file for fish'
42
+ task :fish_complete do
43
+ data = { 'commands' => [], 'details' => [] }
44
+ all_commands = []
45
+ Fronde::CLI::OptParse::FRONDE_COMMANDS.each do |command, options|
46
+ next if options[:alias]
47
+
48
+ data['details'] += (options[:opts] || []).map do |opt|
49
+ comp_opt_to_liquid opt, command
50
+ end
51
+ next if command == 'basic'
52
+
53
+ data['commands'] << command
54
+
55
+ help = I18n.t("fronde.bin.commands.#{command}")
56
+ all_commands << "#{command}\\t'#{help}'"
57
+ end
58
+
59
+ data['comcomp'] = all_commands.join('\n')
60
+
61
+ source = File.expand_path '../fronde/cli/data/fish_completion', __dir__
62
+ template = Liquid::Template.parse(File.read(source))
63
+ puts template.render(data)
64
+ end
33
65
  end