diff options
-rw-r--r-- | yaml/neo20.parse.py | 185 | ||||
-rw-r--r-- | yaml/neo20_global.py | 3 | ||||
-rw-r--r-- | yaml/neo_import.py | 27 | ||||
-rw-r--r-- | yaml/parse_neo.py | 180 | ||||
-rw-r--r-- | yaml/readme.txt | 24 |
5 files changed, 230 insertions, 189 deletions
diff --git a/yaml/neo20.parse.py b/yaml/neo20.parse.py deleted file mode 100644 index 8b6d70a..0000000 --- a/yaml/neo20.parse.py +++ /dev/null @@ -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) diff --git a/yaml/neo20_global.py b/yaml/neo20_global.py deleted file mode 100644 index cf372c1..0000000 --- a/yaml/neo20_global.py +++ /dev/null @@ -1,3 +0,0 @@ -#define box drawing -b = None, None, None, '\u2510', None, '\u2500', '\u250C', '\u252C', None, \ -'\u2518', '\u2502', '\u2524', '\u2514', '\u2534', '\u251C', '\u253C' diff --git a/yaml/neo_import.py b/yaml/neo_import.py new file mode 100644 index 0000000..3a08cc9 --- /dev/null +++ b/yaml/neo_import.py @@ -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')} diff --git a/yaml/parse_neo.py b/yaml/parse_neo.py new file mode 100644 index 0000000..264a4e9 --- /dev/null +++ b/yaml/parse_neo.py @@ -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) diff --git a/yaml/readme.txt b/yaml/readme.txt index 22ad75c..9c31e47 100644 --- a/yaml/readme.txt +++ b/yaml/readme.txt @@ -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
\ No newline at end of file |