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 +4 -4
- data/.github/workflows/test-and-release.yml +1 -0
- data/README.adoc +48 -3
- data/fontist.gemspec +1 -0
- data/lib/fontist/cli/class_options.rb +28 -0
- data/lib/fontist/cli.rb +4 -16
- data/lib/fontist/collection_file.rb +46 -0
- data/lib/fontist/config.rb +62 -0
- data/lib/fontist/config_cli.rb +40 -0
- data/lib/fontist/errors.rb +2 -0
- data/lib/fontist/exclude.yml +1 -0
- data/lib/fontist/font_file.rb +109 -0
- data/lib/fontist/import/google/new_fonts_fetcher.rb +13 -3
- data/lib/fontist/import/google.rb +2 -0
- data/lib/fontist/import/google_import.rb +7 -2
- data/lib/fontist/import/macos.rb +5 -1
- data/lib/fontist/import_cli.rb +8 -1
- data/lib/fontist/system_font.rb +5 -2
- data/lib/fontist/system_index.rb +33 -54
- data/lib/fontist/utils/cache.rb +1 -1
- data/lib/fontist/utils/downloader.rb +2 -2
- data/lib/fontist/utils/file_magic.rb +35 -0
- data/lib/fontist/version.rb +1 -1
- data/lib/fontist.rb +29 -0
- metadata +22 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7df8791fd4754d729546380e67e6c29866f12e4d85bb917b427284c1be610dff
|
4
|
+
data.tar.gz: be7991cacf763d3abc89aeea2841d02b4cc58b7e3a24c99551ee48639b07a3f8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5ec6f6dfa9169caddd99e3641d05864d49bb1bfa2f59ae4887dd72b703c18c599628711fa5f414cb5863832f14751fddc7536cea549358eebbb926231eaf7651
|
7
|
+
data.tar.gz: a87e924b0741861b59114ae75ea93a09ba86eb43510787501f20980a488ec3a181bba20ea0307e6b7f51f83d989c0edaf7db7ea1c74680534eec3280dc1a8d47
|
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/
|
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/
|
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/
|
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
|
data/lib/fontist/errors.rb
CHANGED
@@ -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
|
-
|
34
|
-
|
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
|
@@ -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
|
22
|
+
Fontist::Import::Google::NewFontsFetcher.new(logging: true,
|
23
|
+
limit: @max_count).call
|
19
24
|
end
|
20
25
|
|
21
26
|
def create_formulas(fonts)
|
data/lib/fontist/import/macos.rb
CHANGED
@@ -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(
|
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
|
data/lib/fontist/import_cli.rb
CHANGED
@@ -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
|
|
data/lib/fontist/system_font.rb
CHANGED
@@ -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 =
|
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
|
data/lib/fontist/system_index.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
|
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.
|
10
|
+
name.family
|
10
11
|
end
|
11
12
|
|
12
13
|
def type(name)
|
13
|
-
name.
|
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
|
-
|
24
|
-
|
25
|
-
name.preferred_family
|
24
|
+
name.preferred_family || name.family
|
26
25
|
end
|
27
26
|
|
28
27
|
def type(name)
|
29
|
-
|
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
|
-
|
179
|
+
print_recognition_error(Errors::UnknownFontTypeError.new(path), path)
|
176
180
|
end
|
177
|
-
|
181
|
+
end
|
182
|
+
|
183
|
+
def print_recognition_error(exception, path)
|
178
184
|
Fontist.ui.error(<<~MSG.chomp)
|
179
|
-
#{
|
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
|
-
|
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
|
-
|
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
|
-
|
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:
|
210
|
+
full_name: file.full_name,
|
206
211
|
family_name: family_name,
|
207
|
-
type:
|
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 || {}
|
data/lib/fontist/utils/cache.rb
CHANGED
@@ -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:
|
84
|
-
read_timeout:
|
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
|
data/lib/fontist/version.rb
CHANGED
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.
|
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:
|
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
|