File: scgen.pl

package info (click to toggle)
lyx 1.1.6fix4-2
  • links: PTS
  • area: contrib
  • in suites: woody
  • size: 26,136 kB
  • ctags: 13,679
  • sloc: cpp: 93,591; sh: 9,563; ansic: 8,253; perl: 3,489; makefile: 1,332; tcl: 163; sed: 150; python: 112; yacc: 38
file content (207 lines) | stat: -rw-r--r-- 6,885 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Prolog
%
% Shortcut generator v1.0
%
% This program is known to work with SWI-Prolog version 2.9.5, which you
% can find at
%
%    http://www.swi.psy.uva.nl/usr/jan/SWI-Prolog.html
%
% Purpose: to generate shortcuts for labels in menus and dialogs that are
% guaranteed to be unique within a set of labels. The shortcuts are
% generated in a prioritized manner, such that characters at the beginning
% of words are preferred to characters in the middle of words.
%
% You might find this progam useful if you are translating LyX.
%
% Don't use this file in the development/tools-directory; copy it
% somewhere out of the LyX-distribution tree, unless you're improving
% the tool itself.  The input is to be hard-coded into the file and that
% may cause unnecessary garbage to appear in any patch you're putting
% together.
%
% The labels are supposed to be entered at "LABELS" below,
% and you get one solution (hopefully) with "go.". 
% If there are no solutions, the Prolog-interpretator will reply with a
% "No."
%
% You can get all candidate solutions with "all.", but this requires
% lots of memory.
%
% You can inspect the correspondance between the original strings and
% the prioritized ones with "inspect.".
%
% I have no idea what the big O for the algorithm is, but I suspect it's
% rather steep.
% Asger speculates that the algorithm is O(n^m), where n is the cardinality
% of the candidate sets, while m is the number of sets. Since we do an
% exhausitive search, this has to be the case.

% Predicates:

% print out one solution, i.e. a set of label/shortcut's
% writef/2 may be specific for SWI-prolog
show_one_alternative([]).
show_one_alternative([L/_/C|Rest]):-
  writef('%s|#%n\n',[L,C]),
  show_one_alternative(Rest).

% printout predicate for "all."
show_solutions([]).
show_solutions([H|T]):-
  write('-----------\n'),
  show_one_alternative(H),
  show_solutions(T).

% print out correspondance between original strings and prioritized ones.
show_priority([]).
show_priority([L/P/_|Rest]):-
  writef('%s|%n\n',[L,P]),
  show_priority(Rest).

% character is from a set of allowed characters.
% "AZaz09"=[65, 90, 97, 122, 48, 57]
allowed_char(C):-
  C >= 97, C =< 122. % a-z
allowed_char(C):-
  C >= 65, C =< 90. % A-Z
allowed_char(C):-
  C >= 48, C =< 57. % 0-9

% turn lowercase to uppercase; alt-<key> is case insensitive
uppercase(L,U):-
  (L >= 97, L =< 122) -> U is L - 32;
  U is L.

% possible_char/2: Gets all characters in label, one after one.
possible_char(_/Label,Char):-
  member(Char,Label). 		% the character is part of the label

% prepare_labels/2: Prepares all labels. Constructs a new list of pairs 
% where the original string is coupled with the prepared string.
prepare_labels([], []).
prepare_labels([H1|T1], [H1/H2|T2]):-
	prepare_string(H1, H2),
	prepare_labels(T1, T2).

% prepare_string/2: Prepares a string by removing duplicate characters,
% prioritizing initials letters, removing illegal characters and turning
% lowercase to uppercase characters.
prepare_string(Label,Result):-
  string_to_list(Label,List1),	% make a list of the string
  prioritize(List1, List2),	% Prioritize string
  filter_chars(List2, List3),	% Filter out unwanted chars
  unique(List3, Result). 	% Remove duplicates

% prioritize/2: This predicate rearranges a list, such that
% chars at the beginning of words are put first in the list.
% i.e. prioritize("Foo bar", "Fboo ar")" is true.
prioritize(L1,L2):-
	initial_chars(L1, I),	% Find all initial characters
	subtract(L1, I, Rest),	% and the others
	append(I, Rest, L2).	% and we have the result.

% initial_chars/2: Returns a list of characters that appear at the beginning
% of words. i.e. initial_chars("Foo bar", "Fb") is true.
initial_chars([],[]).
initial_chars([A|T1], [A|T3]):-
	rest_after_space(T1, T2),	% Return rest of list after space
	initial_chars(T2, T3).

% rest_after_space/2: Returns the list after the first space.
% i.e. "rest_after_space("Foo bar", "bar") is true.
rest_after_space([], []).
rest_after_space([32, H1|T1], [H1|T1]):- !.
rest_after_space([_|T1], T2):-
	rest_after_space(T1, T2).

% filterchars/2: Filter outs non-allowed characters from list, and turns
% lowercase to uppercase.
filter_chars([], []).
filter_chars([H|T1], [C|T2]):-
 	allowed_char(H), !, uppercase(H, C),
	filter_chars(T1, T2).
filter_chars([_|T1], T2):-
	filter_chars(T1, T2).

% unique/2: This predicate removes duplicate characters without reordering.
% i.e. unique("Foo bar", "Fo bar") is true.
unique([], []).
unique([H|T1], [H|T3]):-
	delete(T1, H, T2),	% Remove duplicates.
	unique(T2,T3).

% working_shortcuts/2 instantiates Char in the first argument for a whole
% menu/dialog.
working_shortcuts([],_). % end of the list

working_shortcuts([Label/Char|Rest],Used):-
  possible_char(Label,Char), % i.e. part of the label string
  \+member(Char,Used),  % not used by any other shortcut
  working_shortcuts(Rest,[Char|Used]). % and all the other labels have
                                       % shortcuts
% The prolog motor will backtrack up and down the list of labels
% until it finds a set with unique characters for each label


% Label strings goes here.
% Just cut&paste the strings from the LyX-source, and remove any
% control sequences for menus.  We could add a couple of predicates to scan
% a file, but re-consulting this file takes only a fraction of a second
% so I didn't bother to add a fancy user interface here.  The solution is
% printed like <label> '|#' <key>, allthough this isn't nessecarily useful,
% for menus for instance.
%
% The characters are picked with priority from left to right within
% strings, and the labels are listed in falling priority.
% If you want a certain label to have a certain shortcut, try adding that
% character in front of the string (like 'Exit' -> 'xExit') and move it
% higher up in the list.
% If this doesn't work, replace the string with only that character
% ('Exit' -> 'x'). If you get a "No." then, you lose.
% Use "inspect." to inspect the resulting priotized strings.

% LABELS
lab(Labels):-
  Strings = [
"New...",
"New from template...",
"Open...",
"Close",
"Save",
"Save As...",
"Revert to saved",
"View dvi",
"View PostScript",
"Update dvi",
"Update PostScript",
"Print...",
"Fax...",
"Export",
"Exit"
% NB, no comma on the last one. Easy to forget.
  ],
  prepare_labels(Strings, Str),
  bagof(L/_,member(L,Str),Labels).

% Inspect mapping between original string and prioritized ones.
inspect:-
	lab(Labels),
	show_priority(Labels).

% Find ALL solutions (they are often legion - don't bother ;)
all:- % May (probably, on large dialogs) run out on memory.
  lab(Labels),
  setof(Labels,working_shortcuts(Labels,[]),Solutions),
  show_solutions(Solutions).

% Find one solution
one:-
  lab(Labels),
  working_shortcuts(Labels,[]),
  show_one_alternative(Labels).

% Entry point.
go:-
  one.