fontist 1.17.0 → 1.18.2

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: e1c609003084e7675dfd55c7488c57b9f216a7e9f6412e2dd707e589bdb5f11e
4
- data.tar.gz: ff531fc17364227dc60b47eaa64fe5547bc9c1d30e05c94364109d79d7276b5e
3
+ metadata.gz: 7df8791fd4754d729546380e67e6c29866f12e4d85bb917b427284c1be610dff
4
+ data.tar.gz: be7991cacf763d3abc89aeea2841d02b4cc58b7e3a24c99551ee48639b07a3f8
5
5
  SHA512:
6
- metadata.gz: 2bcb373787926878310fa113e4454ac09e203c82708bd2edb3df796ce1e92f7e038a5c54011aade53f7cbc2ac2f20c311e449d5d5304a0235b93bfb0433750de
7
- data.tar.gz: 6ad5b3863ed427316065477a3c873264ffa6d543bb86be696396e61d8f727533bc8bb50268ce8818b45bb15da387e6913b88f2c1a9abb7ed4a4944e0a8d57691
6
+ metadata.gz: 5ec6f6dfa9169caddd99e3641d05864d49bb1bfa2f59ae4887dd72b703c18c599628711fa5f414cb5863832f14751fddc7536cea549358eebbb926231eaf7651
7
+ data.tar.gz: a87e924b0741861b59114ae75ea93a09ba86eb43510787501f20980a488ec3a181bba20ea0307e6b7f51f83d989c0edaf7db7ea1c74680534eec3280dc1a8d47
@@ -45,6 +45,7 @@ jobs:
45
45
  bundler-cache: true
46
46
 
47
47
  - if: matrix.os == 'macos-latest'
48
+ name: Run tests including dev ones
48
49
  run: |
49
50
  brew install lcdf-typetools
50
51
  bundle exec rspec
data/README.adoc CHANGED
@@ -78,6 +78,9 @@ NOTE: See <<preferred-family-change>> for the differences between
78
78
  `-v, --verbose`:: Set the log level to debug. It prints formulas excluded
79
79
  during installation and information for developers of fontist.
80
80
 
81
+ `-c, --no-cache`:: Prefer direct download even when a file is already cached in
82
+ a system.
83
+
81
84
  === Install fonts: `fontist install`
82
85
 
83
86
  Fontist checks whether this font is already installed, and if not, then installs
@@ -299,6 +302,39 @@ Roboto Mono:
299
302
  - "/Users/user/.fontist/fonts/RobotoMono-VariableFont_wght.ttf"
300
303
  ----
301
304
 
305
+ === Work with fontist config: `fontist config`
306
+
307
+ Fontist supports system-wide settings for the following parameters:
308
+
309
+ `open_timeout`:: Sets timeout for opening a connection during download
310
+ (default: 10)
311
+
312
+ `read_timeout`:: Sets timeout for reading the opened connection during download
313
+ (default: 10)
314
+
315
+ Show current attributes in the config:
316
+
317
+ [source,sh]
318
+ ----
319
+ $ fontist config show
320
+ Current config:
321
+ read_timeout: 5
322
+ ----
323
+
324
+ Assign a value to an attribute:
325
+
326
+ [source,sh]
327
+ ----
328
+ $ fontist config set read_timeout 60
329
+ ----
330
+
331
+ Restore a default value of an attribute:
332
+
333
+ [source,sh]
334
+ ----
335
+ $ fontist config delete read_timeout
336
+ ----
337
+
302
338
  === Work with Fontconfig: `fontist fontconfig`
303
339
 
304
340
  Fontconfig is a software designed to provide fonts to other programs. It is
@@ -621,6 +657,15 @@ Apple Support site:
621
657
  WARNING: Fontist does not allow installing macOS-specific fonts on non-macOS
622
658
  platforms due to font license restrictions of those fonts.
623
659
 
660
+ === Known problematic fonts
661
+
662
+ * NISC18030.ttf (GB18030 Bitmap) - macOS, more info in
663
+ https://github.com/fontist/fontist/issues/344[the NISC18030 issue]
664
+
665
+ The full list of known problematic fonts:
666
+
667
+ * https://github.com/fontist/fontist/blob/main/lib/fontist/exclude.yml[List of fonts excluded from usage]
668
+
624
669
 
625
670
  == Advanced usage
626
671
 
@@ -826,7 +871,7 @@ For file paths, specify the file path as argument:
826
871
 
827
872
  [source,sh]
828
873
  ----
829
- wget https://www.latofonts.com/download/lato2ofl-zip/
874
+ wget https://www.latofonts.com/files/Lato2OFL.zip
830
875
  fontist create-formula lato.zip
831
876
  ----
832
877
 
@@ -834,7 +879,7 @@ For URLs, simply specify the URL as the argument:
834
879
 
835
880
  [source,sh]
836
881
  ----
837
- fontist create-formula https://www.latofonts.com/download/lato2ofl-zip/
882
+ fontist create-formula https://www.latofonts.com/files/Lato2OFL.zip
838
883
  # > file created at lato.yml because the file downloaded is lato.zip
839
884
  ----
840
885
 
@@ -843,7 +888,7 @@ private formula repository location.
843
888
 
844
889
  [source,sh]
845
890
  ----
846
- fontist create-formula https://www.latofonts.com/download/lato2ofl-zip/
891
+ fontist create-formula https://www.latofonts.com/files/Lato2OFL.zip
847
892
  cp lato.yml ~/.fontist/formulas/Formulas/
848
893
  ----
849
894
 
data/fontist.gemspec CHANGED
@@ -31,6 +31,7 @@ Gem::Specification.new do |spec|
31
31
 
32
32
  spec.add_runtime_dependency "down", "~> 5.0"
33
33
  spec.add_runtime_dependency "extract_ttc", "~> 0.1"
34
+ spec.add_runtime_dependency "json", "~> 2.0"
34
35
  spec.add_runtime_dependency "nokogiri", "~> 1.0"
35
36
  spec.add_runtime_dependency "mime-types", "~> 3.0"
36
37
  spec.add_runtime_dependency "sys-uname", "~> 1.2"
@@ -1,9 +1,37 @@
1
1
  module Fontist
2
2
  class CLI < Thor
3
3
  module ClassOptions
4
+ # rubocop:disable Metrics/MethodLength
5
+ def self.included(base)
6
+ base.class_option :preferred_family,
7
+ type: :boolean,
8
+ desc: "Use Preferred Family when available"
9
+
10
+ base.class_option :quiet,
11
+ aliases: :q,
12
+ type: :boolean,
13
+ desc: "Hide all messages"
14
+
15
+ base.class_option :verbose,
16
+ aliases: :v,
17
+ type: :boolean,
18
+ desc: "Print debug messages"
19
+
20
+ base.class_option :no_cache,
21
+ aliases: :c,
22
+ type: :boolean,
23
+ desc: "Avoid using cache during download"
24
+
25
+ base.class_option :formulas_path,
26
+ type: :string,
27
+ desc: "Path to formulas"
28
+ end
29
+ # rubocop:enable Metrics/MethodLength
30
+
4
31
  def handle_class_options(options)
5
32
  Fontist.preferred_family = options[:preferred_family]
6
33
  Fontist.log_level = log_level(options)
34
+ Fontist.use_cache = !options[:no_cache]
7
35
 
8
36
  if options[:formulas_path]
9
37
  Fontist.formulas_path = Pathname.new(options[:formulas_path])
data/lib/fontist/cli.rb CHANGED
@@ -4,6 +4,7 @@ require "fontist/repo_cli"
4
4
  require "fontist/cache_cli"
5
5
  require "fontist/import_cli"
6
6
  require "fontist/fontconfig_cli"
7
+ require "fontist/config_cli"
7
8
 
8
9
  module Fontist
9
10
  class CLI < Thor
@@ -58,22 +59,6 @@ module Fontist
58
59
  false
59
60
  end
60
61
 
61
- class_option :preferred_family,
62
- type: :boolean,
63
- desc: "Use Preferred Family when available"
64
-
65
- class_option :quiet,
66
- aliases: :q,
67
- type: :boolean,
68
- desc: "Hide all messages"
69
-
70
- class_option :verbose,
71
- aliases: :v,
72
- type: :boolean,
73
- desc: "Print debug messages"
74
-
75
- class_option :formulas_path, type: :string, desc: "Path to formulas"
76
-
77
62
  desc "install FONT", "Install font"
78
63
  option :force, type: :boolean, aliases: :f,
79
64
  desc: "Install even if already installed in system"
@@ -221,6 +206,9 @@ module Fontist
221
206
  desc "fontconfig SUBCOMMAND ...ARGS", "Manage fontconfig"
222
207
  subcommand "fontconfig", Fontist::FontconfigCLI
223
208
 
209
+ desc "config SUBCOMMAND ...ARGS", "Manage fontist config"
210
+ subcommand "config", Fontist::ConfigCLI
211
+
224
212
  desc "cache SUBCOMMAND ...ARGS", "Manage fontist cache"
225
213
  subcommand "cache", Fontist::CacheCLI
226
214
 
@@ -0,0 +1,46 @@
1
+ require "ttfunk"
2
+
3
+ module Fontist
4
+ class CollectionFile
5
+ include Enumerable
6
+
7
+ class << self
8
+ def from_path(path)
9
+ io = ::File.new(path, "rb")
10
+
11
+ yield new(build_collection(io))
12
+ ensure
13
+ io.close
14
+ end
15
+
16
+ private
17
+
18
+ def build_collection(io)
19
+ TTFunk::Collection.new(io)
20
+ rescue StandardError => e
21
+ raise Errors::FontFileError,
22
+ "Font file could not be parsed: #{e.inspect}."
23
+ end
24
+ end
25
+
26
+ def initialize(ttfunk_collection)
27
+ @collection = ttfunk_collection
28
+ end
29
+
30
+ def count
31
+ @collection.count
32
+ end
33
+
34
+ def each
35
+ count.times do |index|
36
+ yield self[index]
37
+ end
38
+
39
+ self
40
+ end
41
+
42
+ def [](index)
43
+ FontFile.from_collection_index(@collection, index)
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,62 @@
1
+ module Fontist
2
+ class Config
3
+ include Singleton
4
+
5
+ def initialize
6
+ @custom_values = load_config_file
7
+ end
8
+
9
+ def values
10
+ default_values.merge(@custom_values)
11
+ end
12
+
13
+ def custom_values
14
+ @custom_values
15
+ end
16
+
17
+ def set(key, value)
18
+ v = normalize_value(value)
19
+ @custom_values[key.to_s] = v
20
+
21
+ persist
22
+ end
23
+
24
+ def delete(key)
25
+ @custom_values.delete(key.to_s)
26
+
27
+ persist
28
+ end
29
+
30
+ def default_value(key)
31
+ default_values[key.to_s]
32
+ end
33
+
34
+ def default_values
35
+ { open_timeout: 10,
36
+ read_timeout: 10 }.transform_keys(&:to_s)
37
+ end
38
+
39
+ def persist
40
+ FileUtils.mkdir_p(File.dirname(Fontist.config_path))
41
+ File.write(Fontist.config_path, YAML.dump(@custom_values))
42
+ end
43
+
44
+ def load
45
+ @custom_values = load_config_file
46
+ end
47
+
48
+ private
49
+
50
+ def load_config_file
51
+ return {} unless File.exist?(Fontist.config_path)
52
+
53
+ YAML.load_file(Fontist.config_path)
54
+ end
55
+
56
+ def normalize_value(value)
57
+ return value.to_i if value.to_i.to_s == value # detect integer
58
+
59
+ value
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,40 @@
1
+ module Fontist
2
+ class ConfigCLI < Thor
3
+ include CLI::ClassOptions
4
+
5
+ STATUS_SUCCESS = 0
6
+
7
+ desc "show", "Show values of the current config"
8
+ def show
9
+ handle_class_options(options)
10
+ values = Config.instance.custom_values
11
+ Fontist.ui.success("Current config:")
12
+ Fontist.ui.success(format_hash(values))
13
+ STATUS_SUCCESS
14
+ end
15
+
16
+ desc "set KEY VALUE", "Set the KEY attribute to VALUE in the current config"
17
+ def set(key, value)
18
+ handle_class_options(options)
19
+ Config.instance.set(key, value)
20
+ Fontist.ui.success("'#{key}' set to '#{value}'.")
21
+ STATUS_SUCCESS
22
+ end
23
+
24
+ desc "delete KEY", "Delete the KEY attribute from the current config"
25
+ def delete(key)
26
+ handle_class_options(options)
27
+ Config.instance.delete(key)
28
+ Fontist.ui.success(
29
+ "'#{key}' reset to default ('#{Config.instance.default_value(key)}').",
30
+ )
31
+ STATUS_SUCCESS
32
+ end
33
+
34
+ private
35
+
36
+ def format_hash(hash)
37
+ YAML.dump(hash).gsub(/^---.*$/, "").strip
38
+ end
39
+ end
40
+ end
@@ -18,6 +18,8 @@ module Fontist
18
18
 
19
19
  class FontIndexCorrupted < GeneralError; end
20
20
 
21
+ class FontFileError < GeneralError; end
22
+
21
23
  class FontistVersionError < GeneralError; end
22
24
 
23
25
  class FontNotFoundError < GeneralError; end
@@ -0,0 +1 @@
1
+ - NISC18030.ttf
@@ -0,0 +1,109 @@
1
+ require "ttfunk"
2
+
3
+ module Fontist
4
+ class FontFile
5
+ PLATFORM_MACINTOSH = 1
6
+ PLATFORM_MICROSOFT = 3
7
+
8
+ ENCODING_MAC_ROMAN = 0
9
+ ENCODING_MS_UNICODE_BMP = 1
10
+
11
+ LANGUAGE_MAC_ENGLISH = 0
12
+ LANGUAGE_MS_ENGLISH_AMERICAN = 0x409
13
+
14
+ class << self
15
+ def from_path(path)
16
+ content = File.read(path, mode: "rb")
17
+
18
+ from_content(content)
19
+ end
20
+
21
+ def from_content(content)
22
+ new(build_font(content))
23
+ end
24
+
25
+ def from_collection_index(collection, index)
26
+ new(build_font_from_collection_index(collection, index))
27
+ end
28
+
29
+ private
30
+
31
+ def build_font(content)
32
+ TTFunk::File.new(content)
33
+ rescue StandardError => e
34
+ raise_font_file_error(e)
35
+ end
36
+
37
+ def build_font_from_collection_index(collection, index)
38
+ collection[index]
39
+ rescue StandardError => e
40
+ raise_font_file_error(e)
41
+ end
42
+
43
+ def raise_font_file_error(exception)
44
+ raise Errors::FontFileError,
45
+ "Font file could not be parsed: #{exception.inspect}."
46
+ end
47
+ end
48
+
49
+ def initialize(ttfunk_file)
50
+ @file = ttfunk_file
51
+ end
52
+
53
+ def full_name
54
+ english_name(main_name.font_name)
55
+ end
56
+
57
+ def family
58
+ english_name(main_name.font_family)
59
+ end
60
+
61
+ def subfamily
62
+ english_name(main_name.font_subfamily)
63
+ end
64
+
65
+ def preferred_family
66
+ return if main_name.preferred_family.empty?
67
+
68
+ english_name(main_name.preferred_family)
69
+ end
70
+
71
+ def preferred_subfamily
72
+ return if main_name.preferred_subfamily.empty?
73
+
74
+ english_name(main_name.preferred_subfamily)
75
+ end
76
+
77
+ private
78
+
79
+ def main_name
80
+ @main_name ||= @file.name
81
+ end
82
+
83
+ def english_name(name)
84
+ visible_characters(find_english(name))
85
+ end
86
+
87
+ def find_english(name)
88
+ name.find { |x| microsoft_english?(x) } ||
89
+ name.find { |x| mac_english?(x) } ||
90
+ name.last
91
+ end
92
+
93
+ def microsoft_english?(string)
94
+ string.platform_id == PLATFORM_MICROSOFT &&
95
+ string.encoding_id == ENCODING_MS_UNICODE_BMP &&
96
+ string.language_id == LANGUAGE_MS_ENGLISH_AMERICAN
97
+ end
98
+
99
+ def mac_english?(string)
100
+ string.platform_id == PLATFORM_MACINTOSH &&
101
+ string.encoding_id == ENCODING_MAC_ROMAN &&
102
+ string.language_id == LANGUAGE_MAC_ENGLISH
103
+ end
104
+
105
+ def visible_characters(text)
106
+ text.gsub(/[^[:print:]]/, "").to_s
107
+ end
108
+ end
109
+ end
@@ -9,8 +9,9 @@ module Fontist
9
9
  REPO_URL = "https://github.com/google/fonts.git".freeze
10
10
  SKIPLIST_PATH = File.expand_path("skiplist.yml", __dir__)
11
11
 
12
- def initialize(logging: false)
12
+ def initialize(logging: false, limit: nil)
13
13
  @logging = logging
14
+ @limit = limit
14
15
  end
15
16
 
16
17
  def call
@@ -30,11 +31,20 @@ module Fontist
30
31
  end
31
32
 
32
33
  def fetch_new_paths
33
- fetch_fonts_paths.select do |path|
34
- log_font(path) do
34
+ new_paths = []
35
+
36
+ fetch_fonts_paths.each do |path|
37
+ new = log_font(path) do
35
38
  new?(path)
36
39
  end
40
+
41
+ next unless new
42
+
43
+ new_paths << path
44
+ return new_paths if @limit && new_paths.size >= @limit
37
45
  end
46
+
47
+ new_paths
38
48
  end
39
49
 
40
50
  def fetch_fonts_paths
@@ -1,6 +1,8 @@
1
1
  module Fontist
2
2
  module Import
3
3
  module Google
4
+ DEFAULT_MAX_COUNT = 100
5
+
4
6
  def self.metadata_name(path)
5
7
  metadata_path = File.join(path, "METADATA.pb")
6
8
  return unless File.exist?(metadata_path)
@@ -6,16 +6,21 @@ require_relative "create_formula"
6
6
  module Fontist
7
7
  module Import
8
8
  class GoogleImport
9
+ def initialize(options)
10
+ @max_count = options[:max_count] || Google::DEFAULT_MAX_COUNT
11
+ end
12
+
9
13
  def call
10
14
  fonts = new_fonts
11
15
  create_formulas(fonts)
12
- rebuild_index
16
+ rebuild_index unless fonts.empty?
13
17
  end
14
18
 
15
19
  private
16
20
 
17
21
  def new_fonts
18
- Fontist::Import::Google::NewFontsFetcher.new(logging: true).call
22
+ Fontist::Import::Google::NewFontsFetcher.new(logging: true,
23
+ limit: @max_count).call
19
24
  end
20
25
 
21
26
  def create_formulas(fonts)
@@ -8,6 +8,10 @@ module Fontist
8
8
  FONT_XML = "/System/Library/AssetsV2/com_apple_MobileAsset_Font6/com_apple_MobileAsset_Font6.xml".freeze # rubocop:disable Layout/LineLength
9
9
  HOMEPAGE = "https://support.apple.com/en-om/HT211240#document".freeze
10
10
 
11
+ def initialize(font_xml = FONT_XML)
12
+ @font_xml = font_xml
13
+ end
14
+
11
15
  def call
12
16
  links.each do |link|
13
17
  create_formula(link)
@@ -21,7 +25,7 @@ module Fontist
21
25
  private
22
26
 
23
27
  def links
24
- data = Plist.parse_xml(FONT_XML)
28
+ data = Plist.parse_xml(@font_xml)
25
29
  data["Assets"].map do |x|
26
30
  x.values_at("__BaseURL", "__RelativePath").join
27
31
  end
@@ -1,12 +1,19 @@
1
+ require_relative "import/google"
2
+
1
3
  module Fontist
2
4
  class ImportCLI < Thor
3
5
  include CLI::ClassOptions
4
6
 
5
7
  desc "google", "Import Google fonts"
8
+ option :max_count,
9
+ type: :numeric, aliases: :n,
10
+ desc: "Limit the number of formulas to import " \
11
+ "(default is #{Fontist::Import::Google::DEFAULT_MAX_COUNT})."
12
+
6
13
  def google
7
14
  handle_class_options(options)
8
15
  require "fontist/import/google_import"
9
- Fontist::Import::GoogleImport.new.call
16
+ Fontist::Import::GoogleImport.new(options).call
10
17
  CLI::STATUS_SUCCESS
11
18
  end
12
19
 
@@ -16,9 +16,8 @@ module Fontist
16
16
  end
17
17
 
18
18
  def self.load_system_font_paths
19
- config_path = Fontist.system_file_path
20
19
  os = Fontist::Utils::System.user_os.to_s
21
- templates = YAML.load_file(config_path)["system"][os]["paths"]
20
+ templates = system_config["system"][os]["paths"]
22
21
  patterns = expand_paths(templates)
23
22
 
24
23
  Dir.glob(patterns)
@@ -26,6 +25,10 @@ module Fontist
26
25
  # "Case sensitivity depends on your system"
27
26
  end
28
27
 
28
+ def self.system_config
29
+ YAML.load_file(Fontist.system_file_path)
30
+ end
31
+
29
32
  def self.reset_system_font_paths_cache
30
33
  @system_font_paths = nil
31
34
  end
@@ -1,4 +1,5 @@
1
- require "ttfunk"
1
+ require_relative "font_file"
2
+ require_relative "collection_file"
2
3
 
3
4
  module Fontist
4
5
  class SystemIndex
@@ -6,11 +7,11 @@ module Fontist
6
7
 
7
8
  class DefaultFamily
8
9
  def family_name(name)
9
- name.font_family
10
+ name.family
10
11
  end
11
12
 
12
13
  def type(name)
13
- name.font_subfamily
14
+ name.subfamily
14
15
  end
15
16
 
16
17
  def transform_override_keys(dict)
@@ -20,15 +21,11 @@ module Fontist
20
21
 
21
22
  class PreferredFamily
22
23
  def family_name(name)
23
- return name.font_family if name.preferred_family.empty?
24
-
25
- name.preferred_family
24
+ name.preferred_family || name.family
26
25
  end
27
26
 
28
27
  def type(name)
29
- return name.font_subfamily if name.preferred_subfamily.empty?
30
-
31
- name.preferred_subfamily
28
+ name.preferred_subfamily || name.subfamily
32
29
  end
33
30
 
34
31
  def transform_override_keys(dict)
@@ -37,15 +34,6 @@ module Fontist
37
34
  end
38
35
  end
39
36
 
40
- PLATFORM_MACINTOSH = 1
41
- PLATFORM_MICROSOFT = 3
42
-
43
- ENCODING_MAC_ROMAN = 0
44
- ENCODING_MS_UNICODE_BMP = 1
45
-
46
- LANGUAGE_MAC_ENGLISH = 0
47
- LANGUAGE_MS_ENGLISH_AMERICAN = 0x409
48
-
49
37
  ALLOWED_KEYS = %i[path full_name family_name type].freeze
50
38
 
51
39
  def self.system_index
@@ -78,6 +66,10 @@ module Fontist
78
66
  Fontist.preferred_family? ? PreferredFamily.new : DefaultFamily.new
79
67
  end
80
68
 
69
+ def excluded_fonts
70
+ @excluded_fonts ||= YAML.load_file(Fontist.excluded_fonts_path)
71
+ end
72
+
81
73
  def initialize(index_path, font_paths_fetcher, family)
82
74
  @index_path = index_path
83
75
  @font_paths_fetcher = font_paths_fetcher
@@ -166,30 +158,44 @@ module Fontist
166
158
  end
167
159
 
168
160
  def detect_fonts(path)
161
+ return if excluded?(path)
162
+
163
+ gather_fonts(path)
164
+ rescue Errors::FontFileError => e
165
+ print_recognition_error(e, path)
166
+ end
167
+
168
+ def excluded?(path)
169
+ excluded_fonts.include?(File.basename(path))
170
+ end
171
+
172
+ def gather_fonts(path)
169
173
  case File.extname(path).gsub(/^\./, "").downcase
170
174
  when "ttf", "otf"
171
175
  detect_file_font(path)
172
176
  when "ttc"
173
177
  detect_collection_fonts(path)
174
178
  else
175
- raise Errors::UnknownFontTypeError.new(path)
179
+ print_recognition_error(Errors::UnknownFontTypeError.new(path), path)
176
180
  end
177
- rescue StandardError
181
+ end
182
+
183
+ def print_recognition_error(exception, path)
178
184
  Fontist.ui.error(<<~MSG.chomp)
179
- #{$!.message}
185
+ #{exception.inspect}
180
186
  Warning: File at #{path} not recognized as a font file.
181
187
  MSG
188
+ nil
182
189
  end
183
190
 
184
191
  def detect_file_font(path)
185
- content = File.read(path, mode: "rb")
186
- file = TTFunk::File.new(content)
192
+ file = FontFile.from_path(path)
187
193
 
188
194
  parse_font(file, path)
189
195
  end
190
196
 
191
197
  def detect_collection_fonts(path)
192
- TTFunk::Collection.open(path) do |collection|
198
+ CollectionFile.from_path(path) do |collection|
193
199
  collection.map do |file|
194
200
  parse_font(file, path)
195
201
  end
@@ -197,43 +203,16 @@ module Fontist
197
203
  end
198
204
 
199
205
  def parse_font(file, path)
200
- x = file.name
201
- family_name = english_name(@family.family_name(x))
206
+ family_name = @family.family_name(file)
202
207
 
203
208
  {
204
209
  path: path,
205
- full_name: english_name(x.font_name),
210
+ full_name: file.full_name,
206
211
  family_name: family_name,
207
- type: english_name(@family.type(x)),
212
+ type: @family.type(file),
208
213
  }.merge(override_font_props(path, family_name))
209
214
  end
210
215
 
211
- def english_name(name)
212
- visible_characters(find_english(name))
213
- end
214
-
215
- def find_english(name)
216
- name.find { |x| microsoft_english?(x) } ||
217
- name.find { |x| mac_english?(x) } ||
218
- name.last
219
- end
220
-
221
- def microsoft_english?(string)
222
- string.platform_id == PLATFORM_MICROSOFT &&
223
- string.encoding_id == ENCODING_MS_UNICODE_BMP &&
224
- string.language_id == LANGUAGE_MS_ENGLISH_AMERICAN
225
- end
226
-
227
- def mac_english?(string)
228
- string.platform_id == PLATFORM_MACINTOSH &&
229
- string.encoding_id == ENCODING_MAC_ROMAN &&
230
- string.language_id == LANGUAGE_MAC_ENGLISH
231
- end
232
-
233
- def visible_characters(text)
234
- text.gsub(/[^[:print:]]/, "").to_s
235
- end
236
-
237
216
  def override_font_props(path, font_name)
238
217
  override = Formula.find_by_font_file(path)
239
218
  &.style_override(font_name)&.to_h || {}
@@ -9,7 +9,7 @@ module Fontist
9
9
 
10
10
  def fetch(key)
11
11
  map = load_cache
12
- if cache_exist?(map[key])
12
+ if Fontist.use_cache? && cache_exist?(map[key])
13
13
  print(map[key])
14
14
 
15
15
  return downloaded_file(map[key])
@@ -80,8 +80,8 @@ module Fontist
80
80
  def do_download_file_with_progress_bar(progress_bar)
81
81
  Down.download(
82
82
  url,
83
- open_timeout: 10,
84
- read_timeout: 10,
83
+ open_timeout: Fontist.open_timeout,
84
+ read_timeout: Fontist.read_timeout,
85
85
  max_redirects: 10,
86
86
  headers: headers,
87
87
  content_length_proc: ->(content_length) {
@@ -0,0 +1,35 @@
1
+ module Fontist
2
+ module Utils
3
+ class FileMagic
4
+ MAP_MAGIC_TO_TYPE = {
5
+ "\x00\x01\x00\x00\x00" => :ttf,
6
+ "\x4f\x54\x54\x4f" => :otf,
7
+ "\x74\x74\x63\x66" => :ttc,
8
+ }.freeze
9
+
10
+ def self.detect(path)
11
+ new(path).detect
12
+ end
13
+
14
+ def self.max_magic
15
+ @max_magic ||= MAP_MAGIC_TO_TYPE.keys.map(&:bytesize).max
16
+ end
17
+
18
+ def initialize(path)
19
+ @path = path
20
+ end
21
+
22
+ def detect
23
+ beginning = File.binread(@path, self.class.max_magic)
24
+
25
+ MAP_MAGIC_TO_TYPE.each do |magic, type|
26
+ slice = beginning.byteslice(0, magic.bytesize)
27
+
28
+ return type if slice == magic
29
+ end
30
+
31
+ nil
32
+ end
33
+ end
34
+ end
35
+ end
@@ -1,3 +1,3 @@
1
1
  module Fontist
2
- VERSION = "1.17.0".freeze
2
+ VERSION = "1.18.2".freeze
3
3
  end
data/lib/fontist.rb CHANGED
@@ -13,6 +13,7 @@ require "fontist/formula"
13
13
  require "fontist/system_font"
14
14
  require "fontist/manifest"
15
15
  require "fontist/helpers"
16
+ require "fontist/config"
16
17
 
17
18
  module Fontist
18
19
  def self.ui
@@ -75,6 +76,10 @@ module Fontist
75
76
  Fontist.lib_path.join("fontist", "system.yml")
76
77
  end
77
78
 
79
+ def self.excluded_fonts_path
80
+ Fontist.lib_path.join("fontist", "exclude.yml")
81
+ end
82
+
78
83
  def self.system_index_path
79
84
  Fontist.fontist_path.join("system_index.default_family.yml")
80
85
  end
@@ -119,6 +124,30 @@ module Fontist
119
124
  @preferred_family = bool
120
125
  end
121
126
 
127
+ def self.open_timeout
128
+ config[:open_timeout]
129
+ end
130
+
131
+ def self.read_timeout
132
+ config[:read_timeout]
133
+ end
134
+
135
+ def self.config
136
+ Fontist::Config.instance.values
137
+ end
138
+
139
+ def self.config_path
140
+ Fontist.fontist_path.join("config.yml")
141
+ end
142
+
143
+ def self.use_cache?
144
+ instance_variable_defined?("@use_cache") ? @use_cache : true
145
+ end
146
+
147
+ def self.use_cache=(bool)
148
+ @use_cache = bool
149
+ end
150
+
122
151
  def self.log_level=(level)
123
152
  Fontist.ui.level = level
124
153
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fontist
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.17.0
4
+ version: 1.18.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-09-05 00:00:00.000000000 Z
11
+ date: 2024-01-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: down
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0.1'
41
+ - !ruby/object:Gem::Dependency
42
+ name: json
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2.0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '2.0'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: nokogiri
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -305,8 +319,13 @@ files:
305
319
  - lib/fontist/cache_cli.rb
306
320
  - lib/fontist/cli.rb
307
321
  - lib/fontist/cli/class_options.rb
322
+ - lib/fontist/collection_file.rb
323
+ - lib/fontist/config.rb
324
+ - lib/fontist/config_cli.rb
308
325
  - lib/fontist/errors.rb
326
+ - lib/fontist/exclude.yml
309
327
  - lib/fontist/font.rb
328
+ - lib/fontist/font_file.rb
310
329
  - lib/fontist/font_installer.rb
311
330
  - lib/fontist/font_path.rb
312
331
  - lib/fontist/fontconfig.rb
@@ -363,6 +382,7 @@ files:
363
382
  - lib/fontist/utils.rb
364
383
  - lib/fontist/utils/cache.rb
365
384
  - lib/fontist/utils/downloader.rb
385
+ - lib/fontist/utils/file_magic.rb
366
386
  - lib/fontist/utils/locking.rb
367
387
  - lib/fontist/utils/system.rb
368
388
  - lib/fontist/utils/ui.rb