-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
19 changed files
with
566 additions
and
200 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
build/ | ||
instance_ufo/ | ||
master_ufo/ | ||
Lilex (Autosaved).glyphs | ||
Lilex (Autosaved).glyphs | ||
generator/__pycache__ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
[MASTER] | ||
disable= | ||
C0115, # missing-class-docstring | ||
C0116, # missing-function-docstring |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"python.autoComplete.extraPaths": ["./builder"] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
@numbers_dflt a b c d e f A B C D E F |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# Digit color align | ||
# Example: 10:20 | ||
sub @numbers_dflt colon' @numbers_dflt by colon.valign; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
# Multiply align | ||
# Examples: 0xDEADBEEF, 10x2 | ||
sub zero x' @numbers_hex by multiply; | ||
sub @numbers_dflt x' @numbers_dflt by multiply; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# simple lowercase a | ||
sub @lca_dflt by @lca_alt1; | ||
sub @lca_cyrl_dflt by @lca_cyrl_alt1; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
# simple lowercase g | ||
sub @lcg_dflt by @lcg_alt1; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
# slashed number zero | ||
sub zero by zero.alt01; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
# plain number zero | ||
sub zero by zero.alt02; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
# alternate lowercase eszett | ||
sub germandbls by germandbls.alt01; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
|
||
''' | ||
Class helpers | ||
''' | ||
|
||
from typing import List | ||
|
||
denied_symbols = [ | ||
'.notdef', | ||
'NULL', | ||
'CR' | ||
] | ||
|
||
def is_space (symbol: str) -> bool: | ||
return \ | ||
'.liga' in symbol or \ | ||
symbol in denied_symbols or \ | ||
'space' in symbol | ||
|
||
def get_not_space_glyphs (symbols: List[str]) -> List[str]: | ||
return list(filter(lambda x: not is_space(x), symbols)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
''' | ||
fea files helpers | ||
''' | ||
|
||
def read_file (path: str) -> str: | ||
with open(path) as file: | ||
return file.read() | ||
|
||
def read_feature (name: str) -> str: | ||
return read_file(f'./features/{name}.fea') | ||
|
||
def read_class (name: str) -> str: | ||
return read_file(f'./classes/{name}.fea') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
""" | ||
Glyphs.app format processor | ||
""" | ||
|
||
import re | ||
from typing import Union, List, Dict, Tuple | ||
|
||
convert_nl = lambda x: x.replace('\n', "\\012") | ||
|
||
# Determine minimum indentation (first line doesn't count): | ||
class GlyphsFile: | ||
glyphs: List[str] = [] | ||
__raw: str = '' | ||
__path: str | ||
__features: Dict[str, str] | ||
__classes: Dict[str, str] | ||
|
||
def __init__ (self, path: str): | ||
with open(path) as file: | ||
for line in file: | ||
self.__raw += f'{line}' | ||
name = self.__find_glyph_name(line) | ||
if name is not None: | ||
self.glyphs.append(name) | ||
self.__path = path | ||
self.__features = self.__read_list('features') | ||
self.__classes = self.__read_list('classes') | ||
|
||
def flush (self): | ||
file = open(self.__path, 'w') | ||
file.write(self.__raw) | ||
|
||
def set_feature (self, name, value): | ||
self.__features[name] = f'"{convert_nl(value)}"' | ||
self.__write_list('features', self.__features) | ||
|
||
def set_class (self, name, value): | ||
self.__classes[name] = f'"{convert_nl(value)}"' | ||
self.__write_list('classes', self.__classes) | ||
|
||
@property | ||
def ligatures(self): | ||
return list( | ||
map(lambda x: x.replace('.liga', ''), | ||
filter(lambda x: x.endswith('.liga'), self.glyphs))) | ||
|
||
def __find_glyph_name(self, line: str) -> Union[str, None]: | ||
result = re.match(r'glyphname = (.*);', line) | ||
if result is None: | ||
return None | ||
return result.group(1) | ||
|
||
def __read_fields (self, field: str, text_slice: str) -> List[str]: | ||
pattern = re.compile(rf'{field} = (.*)', re.M) | ||
values: List[str] = [] | ||
for value_match in pattern.finditer(text_slice): | ||
values.append(value_match.group(1)[:-1]) | ||
return values | ||
|
||
def __find_definition_index (self, field: str, prefix = '') -> Tuple: | ||
start_index = self.__raw.index(f"{field} = {prefix}") | ||
end_index = self.__raw.index(');', start_index) | ||
return (start_index, end_index + 2) | ||
|
||
def __write_list (self, field: str, value: Dict[str, str]): | ||
start, end = self.__find_definition_index(field) | ||
list_str = '' | ||
for name, code in value.items(): | ||
list_str += ( | ||
'{\n' | ||
f'code = {code};\n' | ||
f'name = {name};\n' | ||
'},\n' | ||
) | ||
self.__raw = ''.join(( | ||
self.__raw[:start], | ||
f'{field} = (\n', | ||
f'{list_str[:-2]}\n' | ||
');', | ||
self.__raw[end:] | ||
)) | ||
|
||
def __read_list (self, field: str): | ||
start, end = self.__find_definition_index(field, prefix='(') | ||
text_slice = self.__raw[start:end + 2] | ||
keys = self.__read_fields('name', text_slice) | ||
values = self.__read_fields('code', text_slice) | ||
|
||
if len(keys) != len(values): | ||
raise Exception('Keys and values count differs') | ||
return dict(zip(keys, values)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
''' | ||
Ligatures feature generator | ||
''' | ||
|
||
from typing import List | ||
|
||
ignore_exceptions = { | ||
'slash_asterisk': [ | ||
"slash' asterisk slash", | ||
"asterisk slash' asterisk" | ||
], | ||
'asterisk_slash': [ | ||
"slash asterisk' slash", | ||
"asterisk' slash asterisk" | ||
], | ||
'asterisk_asterisk': [ | ||
"slash asterisk' asterisk", | ||
"asterisk' asterisk slash" | ||
], | ||
"asterisk_asterisk_asterisk": [ | ||
"slash asterisk' asterisk asterisk", | ||
"asterisk' asterisk asterisk slash", | ||
], | ||
"colon_colon": [ | ||
"colon' colon [less greater]", | ||
"[less greater] colon' colon" | ||
], | ||
"less_less": ["less' less [asterisk plus dollar]"], | ||
"equal_equal": [ | ||
"bracketleft equal' equal", | ||
"equal' equal bracketright", | ||
"equal [colon exclam] equal' equal", | ||
"[less greater bar slash] equal' equal", | ||
"equal' equal [less greater bar slash]", | ||
"equal' equal [colon exclam] equal" | ||
], | ||
"equal_equal_equal": [ | ||
"equal [colon exclam] equal' equal equal", | ||
"[less greater bar slash] equal' equal equal", | ||
"equal' equal equal [less greater bar slash]", | ||
"equal' equal equal [colon exclam] equal", | ||
"bracketleft equal' equal equal", | ||
"equal' equal equal bracketright" | ||
], | ||
"colon_equal": ["equal colon' equal"], | ||
"exclam_equal": ["equal exclam' equal"], | ||
"exclam_equal_equal": ["equal exclam' equal equal"], | ||
"less_equal": [ | ||
"equal less' equal", | ||
"less' equal [less greater bar colon exclam slash]" | ||
], | ||
"greater_equal": [ | ||
"equal greater' equal", | ||
"greater' equal [less greater bar colon exclam slash]" | ||
], | ||
"greater_greater": [ | ||
"[hyphen equal] greater' greater", | ||
"greater' greater hyphen", | ||
"[asterisk plus dollar] greater' greater", | ||
"greater' greater equal [equal less greater bar colon exclam slash]" | ||
], | ||
"bar_bar": [ | ||
"[hyphen equal] bar' bar", | ||
"bar' bar hyphen", | ||
"bar' bar equal [equal less greater bar colon exclam slash]" | ||
], | ||
"slash_slash": [ | ||
"equal slash' slash", | ||
"slash' slash equal" | ||
], | ||
"hyphen_hyphen": [ | ||
"[less greater bar] hyphen' hyphen", | ||
"hyphen' hyphen [less greater bar]" | ||
], | ||
} | ||
|
||
ignore_prefixes = { | ||
'parenleft question': [ | ||
'colon', | ||
'equal' | ||
'exclaim' | ||
], | ||
'less question': ['equal'], | ||
'parenleft question less': [ | ||
'equal', | ||
'exclaim' | ||
], | ||
} | ||
|
||
# Replacemnt ignore templates map | ||
# ignore sub | ||
ignore_templates = { | ||
2: [ | ||
"1 1' 2", | ||
"1' 2 2" | ||
], | ||
3: [ | ||
"1 1' 2 3", | ||
"1' 2 3 3" | ||
], | ||
4: [ | ||
"1 1' 2 3 4", | ||
"1' 2 3 4 4" | ||
] | ||
} | ||
|
||
# Replacemnt templates map | ||
# sub | ||
replace_templates = { | ||
2: [ | ||
"LIG 2' by 1_2.liga", | ||
"1' 2 by LIG" | ||
], | ||
3: [ | ||
"LIG LIG 3' by 1_2_3.liga", | ||
"LIG 2' 3 by LIG", | ||
"1' 2 3 by LIG" | ||
], | ||
4: [ | ||
"LIG LIG LIG 4' by 1_2_3_4.liga", | ||
"LIG LIG 3' 4 by LIG", | ||
"LIG 2' 3 4 by LIG", | ||
"1' 2 3 4 by LIG" | ||
] | ||
} | ||
|
||
def render_statements (statements: List[str], prefix: str) -> str: | ||
return '\n'.join(map(lambda x: f' {prefix} {x};', statements)) | ||
|
||
def render_template (template: str, glyphs: List[str]) -> str: | ||
for i, _ in enumerate(glyphs): | ||
template = template.replace(str(i + 1), glyphs[i]) | ||
return template | ||
|
||
def render_lookup (replace: List[str], ignore: List[str], glyphs: List[str]) -> str: | ||
name = '_'.join(glyphs) | ||
template = ( | ||
f"lookup {name}" + " { \n" | ||
f"{render_statements(ignore, 'ignore sub')}" | ||
f"{render_statements(replace, 'sub')}" | ||
"\n} " + f"{name};" | ||
) | ||
return render_template(template, glyphs) | ||
|
||
def get_ignore_prefixes(name: str, length: int) -> List[str]: | ||
ignores: List[str] = [] | ||
tail = '' | ||
for i in range(length - 1): | ||
tail += f' {i + 1}' | ||
for statement, starts in ignore_prefixes.items(): | ||
for start in starts: | ||
if name.startswith(start): | ||
ignores.append(f"{statement} 1' {tail}") | ||
return ignores | ||
|
||
def render_ligature_lookups (ligatures: List[str]) -> str: | ||
result = "" | ||
for name in ligatures: | ||
glyphs = name.split('_') | ||
lenght = len(glyphs) | ||
ignores = ignore_templates[lenght] + get_ignore_prefixes(name, lenght) | ||
replaces = replace_templates[lenght] | ||
result += render_lookup(replaces, ignores, glyphs) + "\n" | ||
return result |
Oops, something went wrong.