völlige neuüberarbeitung des yaml-Referenzparsers
git-svn-id: https://svn.neo-layout.org@1560 b9310e46-f624-0410-8ea1-cfbb3a30dc96
This commit is contained in:
parent
881ad586c4
commit
f59db1b5cf
5 changed files with 230 additions and 189 deletions
|
@ -1,185 +0,0 @@
|
|||
#YAML Parser for the Neo reference
|
||||
#Copyright 2009 Martin Roppelt (m.p.roppelt ἢτ web in Germany)
|
||||
#
|
||||
#This file is part of German NEO-Layout Version 2.
|
||||
#German Neo Layout Version 2 is free software: you can redistribute it and/or
|
||||
#modify it under the terms of the GNU General Public License as published by the
|
||||
#Free Software Foundation, either version 3 of the License, or (at your option)
|
||||
#any later version. You should have received a copy of the GNU General Public
|
||||
#License along with German NEO-Layout Version 2. If not, see
|
||||
#<http://www.gnu.org/licenses/>.
|
||||
'''
|
||||
Converts the reference into both human and machine readable and editable files
|
||||
for automated creating of keyboard drivers, pictures and references.
|
||||
'''
|
||||
#Needs at least Phyton 3.0 and PyYAML 3.08 (pyyaml.org) to run.
|
||||
#
|
||||
#Call with -h|--help to print command line options.
|
||||
#
|
||||
#Variables:
|
||||
#b: box drawing characters as tuple,
|
||||
#index bits: (0) left (1) down (2) right (3) up
|
||||
##c: control file #for reference
|
||||
#f: file iterator
|
||||
#i: index-sorted file
|
||||
#m: model file
|
||||
#min: miniatures
|
||||
#n: name/number iterator
|
||||
#o: command line options:
|
||||
#o.a: auto-completion of file names as boolean
|
||||
#o.d: destination file name
|
||||
#o.i: index-sorted file name
|
||||
#o.m: model file name
|
||||
#o.r: paths relative to ./ otherwise to ../A-REFERENZ-A/ as boolean
|
||||
#o.s: source file name
|
||||
#o.t: destination file types (i/m/p/v)
|
||||
#o.v: view file name
|
||||
#p: pattern file
|
||||
#pm: pre-model
|
||||
#r: compiled regular expression
|
||||
#s: source file as string
|
||||
#v: view file, contains:
|
||||
#pv: pre-view
|
||||
# string literals
|
||||
# replacement commands
|
||||
# patterns
|
||||
|
||||
from neo20_global import b
|
||||
from optparse import OptionParser, make_option
|
||||
from sys import stdout
|
||||
from unicodedata import category
|
||||
import os
|
||||
import re
|
||||
import yaml
|
||||
|
||||
def parse(s, w = 5):
|
||||
'''
|
||||
Returns a representation of a key field s with the standard with w.
|
||||
'''
|
||||
#Variables:
|
||||
#i: line iterator
|
||||
#j: level iterator
|
||||
#l: key line iterator
|
||||
#y: key level list
|
||||
#m: model
|
||||
#k: key iterator
|
||||
#s: key field as string
|
||||
#w: standard key with
|
||||
#v: view
|
||||
#q: key iterator
|
||||
m = []; v = []; y = []; i = 0
|
||||
for l in [l[:s.index(b[3])] for l in s.splitlines()[1:]]:
|
||||
if l[0] in (b[12], b[14]):
|
||||
m.append([]); v.append([])
|
||||
for j, l in enumerate(y[::-1]):
|
||||
q = 0
|
||||
for k in l[1:].split(b[10]):
|
||||
if j == 0:
|
||||
m[i].append([]); v[i].append([])
|
||||
if len(k) == w:
|
||||
if w == 7:
|
||||
m[i][q].extend([k[0], k[2:5], k[6:7]])
|
||||
elif w == 5:
|
||||
m[i][q].extend(list(k[0:5:2]))
|
||||
elif w == 1:
|
||||
m[i][q] = k
|
||||
else:
|
||||
v[i][q] = k
|
||||
q += 1
|
||||
i += 1; y = []
|
||||
else:
|
||||
y.append(l)
|
||||
return m, v
|
||||
|
||||
def compare(m, min):
|
||||
'''
|
||||
Compares the overall and miniature key field and returns their completed
|
||||
views.
|
||||
'''
|
||||
v = [m[1] for m in m]
|
||||
return v
|
||||
|
||||
#command line options:
|
||||
o = OptionParser(usage = 'example: %prog -ti -astest',
|
||||
description = 'YAML Parser for the Neo reference',
|
||||
option_list = [
|
||||
make_option('-a', action = 'store_true', default = False, help = 'source file \
|
||||
name is inserted into ‘neo20-’ and ‘.txt’'),
|
||||
make_option('-r', action = 'store_false', default = True, help = 'source and \
|
||||
destination files are not relative to ../A-REFERENZ-A/'),
|
||||
make_option('-t', metavar = 'mxiv', default = 'm', help = 'destination file \
|
||||
types (default = %default)'),
|
||||
make_option('-s', metavar = 'source file', default = 'neo20.txt',
|
||||
help = 'default = %default'),
|
||||
make_option('-d', metavar = 'destination file name', help = 'default = *.*'),
|
||||
make_option('-m', metavar = 'model file', help = 'default = *.model'),
|
||||
make_option('-x', metavar = 'hex model file', help = 'default = *.x'),
|
||||
make_option('-i', metavar = 'index-sorted file', help = 'default = *.index'),
|
||||
make_option('-v', metavar = 'view file', help = 'default = *.view')]
|
||||
).parse_args()[0]
|
||||
|
||||
#evaluate options:
|
||||
o.t = o.t.lower()
|
||||
if o.d == None:
|
||||
o.d = o.s.rsplit('.txt')[0]
|
||||
if o.a:
|
||||
o.s, o.d = 'neo20-' + o.s + '.txt', 'neo20-' + o.d
|
||||
if o.r:
|
||||
o.s, o.d = '../A-REFERENZ-A/' + o.s, '../A-REFERENZ-A/' + o.d
|
||||
for f in '.model', '.x', '.index', '.view':
|
||||
if f[1] in o.t.lower() and eval('o.' + f[1]) == None:
|
||||
exec('o.' + f[1] + ' = o.d + f')
|
||||
|
||||
#input:
|
||||
s = open(o.s, encoding = 'utf8').read()
|
||||
|
||||
#processing:
|
||||
r = re.compile(b[6] + '.*?' + b[9] + '.*?\n(?=\n)', re.DOTALL | re.MULTILINE)
|
||||
p, pm = r.split(s), r.findall(s) #Split into key fields and the rest
|
||||
for n in (0, 16):
|
||||
p.insert(n, p.pop(n) + pm.pop(n) + p.pop(n)) #Put the legends back into the
|
||||
#pattern list
|
||||
|
||||
#parse key fields
|
||||
m = [parse(pm[9]), parse(pm[20], 7)]
|
||||
min = []
|
||||
for n in range(6):
|
||||
min.append([parse(pm[10 + n], 1), parse(pm[21+ n], 7)])
|
||||
v = compare(m, min); m = [m[0] for m in m]
|
||||
|
||||
#complete view ##
|
||||
v = [[v], []]
|
||||
|
||||
v.append(p)
|
||||
|
||||
#create hex model
|
||||
if 'x' in o.t.lower():
|
||||
x = []
|
||||
for f, n in enumerate(m):
|
||||
x.append(); ##
|
||||
|
||||
#create index
|
||||
if 'i' in o.t.lower():
|
||||
i = []
|
||||
for n in m:
|
||||
for n in n:
|
||||
i.extend(n)
|
||||
#output:
|
||||
for f in 'mxiv':
|
||||
if not stdout.isatty():
|
||||
file = stdout
|
||||
else:
|
||||
file = open(eval('o.' + f), 'w', encoding = 'utf8')
|
||||
if f in o.t:
|
||||
if f == 'v':
|
||||
yaml.dump_all(v[0:-1], file, allow_unicode = True,
|
||||
explicit_start = True,
|
||||
explicit_end = True)
|
||||
yaml.dump(v.pop(), file, allow_unicode = True,
|
||||
explicit_start = True,
|
||||
explicit_end = True,
|
||||
default_style = '|')
|
||||
else:
|
||||
yaml.dump(eval(f), file, allow_unicode = True,
|
||||
explicit_start = True,
|
||||
explicit_end = True)
|
|
@ -1,3 +0,0 @@
|
|||
#define box drawing
|
||||
b = None, None, None, '\u2510', None, '\u2500', '\u250C', '\u252C', None, \
|
||||
'\u2518', '\u2502', '\u2524', '\u2514', '\u2534', '\u251C', '\u253C'
|
27
yaml/neo_import.py
Normal file
27
yaml/neo_import.py
Normal file
|
@ -0,0 +1,27 @@
|
|||
#===============================================================================
|
||||
# Imports:
|
||||
#===============================================================================
|
||||
#===============================================================================
|
||||
# define box drawings:
|
||||
# index bits: (0) left (1) down (2) right (3) up
|
||||
#===============================================================================
|
||||
|
||||
box_drawings = None, None, None, '\u2510', \
|
||||
None, '\u2500', '\u250C', '\u252C', \
|
||||
None, '\u2518', '\u2502', '\u2524', \
|
||||
'\u2514', '\u2534', '\u251C', '\u253C'
|
||||
|
||||
#===============================================================================
|
||||
# Defaults:
|
||||
#===============================================================================
|
||||
|
||||
reference_directory = '../A-REFERENZ-A/'
|
||||
file_name_append_start = 'neo20-'
|
||||
file_name_append_end = '.txt'
|
||||
file_name_standard_extension = file_name_append_end
|
||||
|
||||
# synchronize with program!
|
||||
file_extensions_mapping = {('model_file', 'm'):('.model','model'),
|
||||
('hex_model_file', 'x'):('.hex', 'hex_model'),
|
||||
('index_sorted_file', 'i'):('.index', 'index'),
|
||||
('view_file', 'v'):('.view', 'view')}
|
180
yaml/parse_neo.py
Normal file
180
yaml/parse_neo.py
Normal file
|
@ -0,0 +1,180 @@
|
|||
#===============================================================================
|
||||
# YAML Parser for the Neo reference
|
||||
# Copyright 2009 Martin Roppelt (m.p.roppelt ἢτ web in Germany)
|
||||
#
|
||||
# This file is part of German NEO-Layout Version 2.
|
||||
# German Neo Layout Version 2 is free software: you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or (at your
|
||||
# option) any later version. You should have received a copy of the GNU General
|
||||
# Public License along with German NEO-Layout Version 2. If not, see
|
||||
# <http://www.gnu.org/licenses/>.
|
||||
#===============================================================================
|
||||
'''
|
||||
Converts the reference into both human and machine readable and editable files
|
||||
for automated creating of keyboard drivers, pictures and references.
|
||||
'''
|
||||
#===============================================================================
|
||||
# Needs at least Phyton 3.0 and PyYAML 3.08 (pyyaml.org) to run.
|
||||
#
|
||||
# Call with -h|--help to print command line options.
|
||||
#===============================================================================
|
||||
|
||||
#===============================================================================
|
||||
# To Do:
|
||||
#===============================================================================
|
||||
|
||||
from neo_import import * #neo shared, settings and function module
|
||||
from optparse import make_option, OptionParser #command line analyzing module
|
||||
import re #regular expression processing module: compile
|
||||
import sys #system module: stdout
|
||||
import yaml #YAML processing module: dump
|
||||
|
||||
#===============================================================================
|
||||
# analyze command line options:
|
||||
#===============================================================================
|
||||
options = OptionParser(usage = 'example: %prog -ti -astest', description = 'YAML Parser for the Neo reference',
|
||||
option_list = [
|
||||
make_option('-a', '--append', '--neo20-txt', action = 'store_true', default = False, help = 'source file name is inserted into ‘' + file_name_append_start + '’ and ‘' + file_name_append_end + '’'),
|
||||
make_option('-r', '--path-not-relative', dest = 'path_relative', action = 'store_false', default = True, help = 'source and destination files are not relative to ' + reference_directory),
|
||||
make_option('-t', '--types', metavar = 'mxiv', default = 'm', help = 'destination file types (default = %default)'),
|
||||
make_option('-s', '--source-file', metavar = 'source file', default = 'neo20.txt', help = 'default = %default'),
|
||||
make_option('-d', '--destination-file', metavar = 'destination file', help = 'default = *.*'),
|
||||
make_option('-m', '--model-file', metavar = 'model file', help = 'default = *.model'),
|
||||
make_option('-x', '--hex-model-file', metavar = 'hex model file', help = 'default = *.x'),
|
||||
make_option('-i', '--index-sorted-file', metavar = 'index-sorted file', help = 'default = *.index'),
|
||||
make_option('-v', '--view-file', metavar = 'view file', help = 'default = *.view'),
|
||||
make_option('-p', '--plain-panel', '--without-legend', dest = 'without_legend', action = 'store_true', default = False, help = 'plain panel reference (without legends)'),
|
||||
make_option('-w', '--key-level-width', type = 'int', metavar = 'int', default = 1, help = 'default = %default'),
|
||||
make_option('-W', '--key-level-delimiter-width', type = 'int', metavar = 'int', default = 1, help = 'default = %default'),
|
||||
make_option('-f', '--key-level-delimiter-filler', metavar = 'char',default = " ", help = 'default = %default'),
|
||||
make_option('-D', '--key-level-delimiter', metavar = 'char'),
|
||||
make_option('-l', '--key-levels-per-line', type = 'int', metavar = 'int', default = 3, help = 'default = %default')
|
||||
]).parse_args()[0]
|
||||
if options.destination_file == None:
|
||||
options.destination_file = options.source_file.rsplit(file_name_standard_extension)[0]
|
||||
if options.append:
|
||||
options.source_file = file_name_append_start + options.source_file + file_name_append_end
|
||||
options.destination_file = file_name_append_start + options.destination_file
|
||||
if options.path_relative:
|
||||
options.source_file = reference_directory + options.source_file
|
||||
options.destination_file = reference_directory + options.destination_file
|
||||
for option, type in file_extensions_mapping:
|
||||
if type in options.types and eval('options.' + option) == None:
|
||||
exec('options.' + option + '=\'' + options.destination_file + file_extensions_mapping[option, type][0] + '\'')
|
||||
if options.key_level_delimiter == None:
|
||||
options.key_level_delimiter = "".ljust(options.key_level_delimiter_width, options.key_level_delimiter_filler)
|
||||
|
||||
#===============================================================================
|
||||
# functions:
|
||||
#===============================================================================
|
||||
|
||||
# assumption: no delimiters around key level block
|
||||
def parse_key_panel(key_panel, key_width = 5):
|
||||
'''
|
||||
returns the model and view representing key_panel,
|
||||
which contain lists for each key row,
|
||||
which contain lists for each key in the key row,
|
||||
which are lists for the key level strings.
|
||||
|
||||
'''
|
||||
return_model = []; return_view = []; key_row = []; key_row_index = 0 # initialization
|
||||
for row in [row[:key_panel.index(box_drawings[3])] for row in key_panel.splitlines()[1:]]: # omit beginning and ending box drawings
|
||||
if row[0] in (box_drawings[12], box_drawings[14]): # if row begins with ├ or │,
|
||||
return_model.append([]); return_view.append([]) # create key row list
|
||||
key_lines = []
|
||||
for key_line_index, key_line in enumerate(key_row[:: - 1]): # reverse lines
|
||||
for key_index, key in enumerate(key_line[1:].split(box_drawings[10])): # split key line into keys
|
||||
if key_line_index == 0: # if bottom line,
|
||||
return_model[key_row_index].append([]); key_lines.append([]); return_view[key_row_index].append([]) # create key list
|
||||
if len(key) == key_width: # if default key, parse line levels:
|
||||
if options.key_level_width == 1 and key_width == 7: # if Neo 2 keypad key:
|
||||
if key[1] == key[5] == options.key_level_delimiter:
|
||||
key_lines[key_index].extend([key[0], key[2:5], key[6]])
|
||||
elif key[::2] == options.key_level_delimiter * 4:
|
||||
key_lines[key_index].extend(key[1::2])
|
||||
else:
|
||||
return_view[key_row_index][key_index].append(key)
|
||||
elif key_width == options.key_level_width * options.key_levels_per_line + (options.key_levels_per_line - 1) * options.key_level_delimiter_width:
|
||||
key_lines[key_index].extend([key[:options.key_level_width] for key in key[:key_width:options.key_level_width + options.key_level_delimiter_width]])
|
||||
elif key_width == options.key_level_width:
|
||||
key_lines[key_index].append(key)
|
||||
else:
|
||||
if options.key_level_width == 1 and key_width == 7 and len(key) == 15: # if Neo 2 keypad key:
|
||||
key_lines[key_index].extend([key[2], key[6:9], key[12]])
|
||||
else:
|
||||
return_view[key_row_index][key_index].append(key)
|
||||
if key_lines != []:
|
||||
for key_level_index, level in enumerate(key_lines[0]):
|
||||
for key_line_index, line_index in enumerate(key_lines):
|
||||
return_model[key_row_index][key_index].append(key_lines[key_line_index][key_level_index])
|
||||
key_row_index += 1; key_row = []
|
||||
else:
|
||||
key_row.append(row)
|
||||
return return_model, return_view
|
||||
|
||||
def compare_model(model, miniature_model):
|
||||
'''
|
||||
Compares the overall and miniature key field and returns their completed
|
||||
views.
|
||||
'''
|
||||
return [model[1] for model in model]
|
||||
|
||||
#===============================================================================
|
||||
# read in reference:
|
||||
#===============================================================================
|
||||
source = open(options.source_file, encoding = 'utf8').read()
|
||||
|
||||
#===============================================================================
|
||||
# split reference into lists of key panels and illustrative text patterns
|
||||
#===============================================================================
|
||||
# searches for ┌…┘ and the following line:
|
||||
regex = re.compile(box_drawings[6] + '.*?' + box_drawings[9] + '.*?\n(?=\n)', re.DOTALL | re.MULTILINE)
|
||||
|
||||
legends, key_panels = regex.split(source), regex.findall(source) # split into lists of key panels and illustrative texts
|
||||
if options.without_legend == False:
|
||||
for legend_index in (0, 16):
|
||||
legends.insert(legend_index, legends.pop(legend_index)+ key_panels.pop(legend_index) + legends.pop(legend_index)) # put the legends back into the pattern list
|
||||
|
||||
#parse key fields
|
||||
model = [parse_key_panel(key_panels[9]), parse_key_panel(key_panels[20], 7)]
|
||||
miniature_models = []
|
||||
for miniature_models_index in range(6):
|
||||
miniature_models.append([parse_key_panel(key_panels[10 + miniature_models_index], 1), parse_key_panel(key_panels[21 + miniature_models_index], 7)])
|
||||
view = compare_model(model, miniature_models) # complete views via comparing key widths
|
||||
model = [model[0] for model in model] # strip views
|
||||
|
||||
# complete view ##
|
||||
view = [[view], [], legends]
|
||||
|
||||
|
||||
# create hex model
|
||||
if 'x' in options.types:
|
||||
hex_model = []
|
||||
for row_index, row in enumerate(model):
|
||||
hex_model.append([])
|
||||
for key_index, key in enumerate(row):
|
||||
hex_model[row_index].append([])
|
||||
for level in key:
|
||||
if len(level) == 1:
|
||||
hex_index[row_index][key_index].append(hex(ord(level))[2:].rjust(4,' '))
|
||||
|
||||
# create index
|
||||
if 'i' in options.types:
|
||||
index = []
|
||||
for n in model:
|
||||
for n in n:
|
||||
i.extend(n)
|
||||
|
||||
# output:
|
||||
for option, type in file_extensions_mapping:
|
||||
if type in options.types:
|
||||
if not sys.stdout.isatty():
|
||||
file = sys.stdout
|
||||
else:
|
||||
file = open(eval('options.' + option), 'w', encoding = 'utf8')
|
||||
if type == 'v':
|
||||
yaml.dump_all(view[0: - 1], file, allow_unicode = True)
|
||||
yaml.dump(view.pop(), file, explicit_start = True, allow_unicode = True, default_style = '|')
|
||||
else:
|
||||
yaml.dump(eval(file_extensions_mapping[option, type][1]), file, allow_unicode = True)
|
|
@ -36,4 +36,26 @@ rasch aus Belegungen Neo-3-Treiber und Forks erstellen.
|
|||
Projektstatus:
|
||||
Zur Zeit entwickele ich einen Parser für die Referenz. Danach möchte ich ein
|
||||
Skript für die Erstellung der neo20.txt aus der maschinenlesbaren Referenz
|
||||
schreiben.
|
||||
schreiben. Dann soll ein Skript zur Umwandlung des Models in xkbmap, xmodmap,
|
||||
ahk und kbdneo folgen, unter berücksichtigung der verwendeten Tastatur (Qwertz,
|
||||
Qwerty, Plum, Kbdneo).
|
||||
|
||||
Abriss:
|
||||
neo_import.py
|
||||
neo_parse.py
|
||||
neo_edit.py
|
||||
neo_make.py
|
||||
ahk_make.py
|
||||
ahk_parse.py
|
||||
hex_parse.py
|
||||
kbd_parse.py
|
||||
kbd_make.py
|
||||
xkb_parse.py
|
||||
xkb_parse.py
|
||||
mod_parse.py
|
||||
mod_make.py
|
||||
mac_parse.py
|
||||
mac_make.py
|
||||
map_parse.py
|
||||
svg_parse.py
|
||||
svg_make.py
|
Loading…
Reference in a new issue