Usual UI message handling...
[blender.git] / release / scripts / modules / bl_i18n_utils / utils_spell_check.py
1 # ##### BEGIN GPL LICENSE BLOCK #####
2 #
3 #  This program is free software; you can redistribute it and/or
4 #  modify it under the terms of the GNU General Public License
5 #  as published by the Free Software Foundation; either version 2
6 #  of the License, or (at your option) any later version.
7 #
8 #  This program is distributed in the hope that it will be useful,
9 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
10 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 #  GNU General Public License for more details.
12 #
13 #  You should have received a copy of the GNU General Public License
14 #  along with this program; if not, write to the Free Software Foundation,
15 #  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 #
17 # ##### END GPL LICENSE BLOCK #####
18
19 # <pep8 compliant>
20
21 import enchant
22 import os
23 import pickle
24 import re
25
26
27 class SpellChecker():
28     """
29     A basic spell checker.
30     """
31
32     # These must be all lower case for comparisons
33     uimsgs = {
34         # OK words
35         "aren",  # aren't
36         "betweens",  # yuck! in-betweens!
37         "boolean", "booleans",
38         "couldn",  # couldn't
39         "decrement",
40         "derivate",
41         "doesn",  # doesn't
42         "equi",  # equi-angular, etc.
43         "fader",
44         "globbing",
45         "hasn",  # hasn't
46         "hetero",
47         "hoc",  # ad-hoc
48         "indices",
49         "iridas",
50         "isn",  # isn't
51         "iterable",
52         "kyrgyz",
53         "latin",
54         "merchantability",
55         "mplayer",
56         "pong",  # ping pong
57         "teleport", "teleporting",
58         "vertices",
59
60         # Merged words
61         "addon", "addons",
62         "antialiasing",
63         "arcsine", "arccosine", "arctangent",
64         "autoclip",
65         "autocomplete",
66         "autoexec",
67         "autoexecution",
68         "autoname",
69         "autopack",
70         "autosave",
71         "autoscale",
72         "autosmooth",
73         "autosplit",
74         "backface", "backfacing",
75         "backimage",
76         "backscattered",
77         "bandnoise",
78         "bindcode",
79         "bitflag", "bitflags",
80         "bitrate",
81         "blackbody",
82         "blendfile",
83         "blendin",
84         "bonesize",
85         "boundbox",
86         "boxpack",
87         "buffersize",
88         "builtin", "builtins",
89         "bytecode",
90         "chunksize",
91         "customdata",
92         "dataset", "datasets",
93         "de",
94         "deconstruct",
95         "defocus",
96         "denoise",
97         "deselect", "deselecting", "deselection",
98         "despill", "despilling",
99         "editcurve",
100         "editmesh",
101         "filebrowser",
102         "filelist",
103         "filename", "filenames",
104         "filepath", "filepaths",
105         "forcefield", "forcefields",
106         "fulldome", "fulldomes",
107         "fullscreen",
108         "gridline",
109         "hemi",
110         "inbetween",
111         "inscatter", "inscattering",
112         "libdata",
113         "lightless",
114         "lineset",
115         "linestyle",
116         "localview",
117         "lookup", "lookups",
118         "mathutils",
119         "midlevel",
120         "midground",
121         "mixdown",
122         "multi",
123         "multifractal",
124         "multires", "multiresolution",
125         "multisampling",
126         "multitexture",
127         "multiuser",
128         "namespace",
129         "keyconfig",
130         "online",
131         "playhead",
132         "popup", "popups",
133         "pre",
134         "precache", "precaching",
135         "precalculate",
136         "prefetch",
137         "premultiply", "premultiplied",
138         "prepass",
139         "prepend",
140         "preprocess", "preprocessing",
141         "preseek",
142         "promillage",
143         "pushdown",
144         "raytree",
145         "readonly",
146         "realtime",
147         "rekey",
148         "remesh",
149         "reprojection",
150         "resize",
151         "restpose",
152         "retarget", "retargets", "retargeting", "retargeted",
153         "rigidbody",
154         "ringnoise",
155         "rolloff",
156         "runtime",
157         "screencast", "screenshot", "screenshots",
158         "selfcollision",
159         "shadowbuffer", "shadowbuffers",
160         "singletexture",
161         "spellcheck", "spellchecking",
162         "startup",
163         "stateful",
164         "starfield",
165         "subflare", "subflares",
166         "subframe", "subframes",
167         "subclass", "subclasses", "subclassing",
168         "subdirectory", "subdirectories", "subdir", "subdirs",
169         "submodule", "submodules",
170         "subpath",
171         "subsize",
172         "substep", "substeps",
173         "targetless",
174         "textbox", "textboxes",
175         "tilemode",
176         "timestamp", "timestamps",
177         "timestep", "timesteps",
178         "todo",
179         "un",
180         "unbake",
181         "uncomment",
182         "unculled",
183         "undeformed",
184         "undistort", "undistortion",
185         "ungroup", "ungrouped",
186         "unhide",
187         "unindent",
188         "unkeyed",
189         "unpremultiply",
190         "unprojected",
191         "unreacted",
192         "unregister",
193         "unselected", "unselectable",
194         "unsubdivided", "unsubdivide",
195         "unshadowed",
196         "unspill",
197         "unstitchable",
198         "vectorscope",
199         "whitespace", "whitespaces",
200         "worldspace",
201         "workflow",
202
203         # Neologisms, slangs
204         "affectable",
205         "animatable",
206         "automagic", "automagically",
207         "blobby",
208         "blockiness", "blocky",
209         "collider", "colliders",
210         "deformer", "deformers",
211         "determinator",
212         "editability",
213         "keyer",
214         "lacunarity",
215         "numerics",
216         "occluder", "occluders",
217         "passepartout",
218         "perspectively",
219         "pixelate",
220         "polygonization", "polygonalization",  # yuck!
221         "selectability",
222         "slurph",
223         "stitchable",
224         "symmetrize",
225         "trackability",
226         "transmissivity",
227         "rasterized", "rasterization", "rasterizer",
228         "renderer", "renderable", "renderability",
229
230         # Really bad!!!
231         "convertor",
232
233         # Abbreviations
234         "aero",
235         "amb",
236         "anim",
237         "bool",
238         "calc",
239         "config", "configs",
240         "const",
241         "coord", "coords",
242         "degr",
243         "diff",
244         "dof",
245         "dupli", "duplis",
246         "eg",
247         "esc",
248         "expr",
249         "fac",
250         "fra",
251         "frs",
252         "grless",
253         "http",
254         "init",
255         "kbit", "kb",
256         "lang", "langs",
257         "lclick", "rclick",
258         "lensdist",
259         "loc", "rot", "pos",
260         "lorem",
261         "luma",
262         "mem",
263         "multicam",
264         "num",
265         "ok",
266         "orco",
267         "ortho",
268         "persp",
269         "pref", "prefs",
270         "prev",
271         "param",
272         "premul",
273         "quad", "quads",
274         "quat", "quats",
275         "recalc", "recalcs",
276         "refl",
277         "sce",
278         "sel",
279         "spec",
280         "struct", "structs",
281         "sys",
282         "tex",
283         "tri", "tris",
284         "uv", "uvs", "uvw", "uw", "uvmap",
285         "ve",
286         "vec",
287         "vel",  # velocity!
288         "vert", "verts",
289         "vis",
290         "xor",
291         "xyz", "xzy", "yxz", "yzx", "zxy", "zyx",
292         "xy", "xz", "yx", "yz", "zx", "zy",
293
294         # General computer/science terms
295         "bitangent",
296         "boid", "boids",
297         "equisolid",
298         "euler", "eulers",
299         "fribidi",
300         "gettext",
301         "hashable",
302         "hotspot",
303         "intrinsics",
304         "isosurface",
305         "jitter", "jittering", "jittered",
306         "keymap", "keymaps",
307         "lambertian",
308         "laplacian",
309         "metadata",
310         "msgfmt",
311         "nand", "xnor",
312         "normals",
313         "numpad",
314         "octree",
315         "omnidirectional",
316         "opengl",
317         "openmp",
318         "photoreceptor",
319         "poly",
320         "polyline", "polylines",
321         "pulldown", "pulldowns",
322         "quantized",
323         "samplerate",
324         "scrollback",
325         "scrollbar",
326         "scroller",
327         "searchable",
328         "spacebar",
329         "tooltip", "tooltips",
330         "trackpad",
331         "tuple",
332         "unicode",
333         "viewport", "viewports",
334         "viscoelastic",
335         "wildcard", "wildcards",
336
337         # General computer graphics terms
338         "anaglyph",
339         "bezier", "beziers",
340         "bicubic",
341         "bilinear",
342         "binormal",
343         "blackpoint", "whitepoint",
344         "blinn",
345         "bokeh",
346         "catadioptric",
347         "centroid",
348         "chrominance",
349         "codec", "codecs",
350         "collada",
351         "compositing",
352         "crossfade",
353         "deinterlace",
354         "dropoff",
355         "dv",
356         "eigenvectors",
357         "equirectangular",
358         "fisheye",
359         "framerate",
360         "gimbal",
361         "grayscale",
362         "icosphere",
363         "inpaint",
364         "lightmap",
365         "lossless", "lossy",
366         "matcap",
367         "midtones",
368         "mipmap", "mipmaps", "mip",
369         "ngon", "ngons",
370         "ntsc",
371         "nurb", "nurbs",
372         "perlin",
373         "phong",
374         "qi",
375         "radiosity",
376         "raycasting",
377         "raytrace", "raytracing", "raytraced",
378         "renderfarm",
379         "scanfill",
380         "shader", "shaders",
381         "specular", "specularity",
382         "spillmap",
383         "sobel",
384         "texel",
385         "tonemap",
386         "toon",
387         "timecode",
388         "voronoi",
389         "voxel", "voxels",
390         "vsync",
391         "wireframe",
392         "zmask",
393         "ztransp",
394
395         # Blender terms
396         "audaspace",
397         "bbone",
398         "breakdowner",
399         "bspline",
400         "bweight",
401         "colorband",
402         "datablock", "datablocks",
403         "despeckle",
404         "dopesheet",
405         "dupliface", "duplifaces",
406         "dupliframe", "dupliframes",
407         "dupliobject", "dupliob",
408         "dupligroup",
409         "duplivert",
410         "dyntopo",
411         "editbone",
412         "editmode",
413         "fcurve", "fcurves",
414         "fedge", "fedges",
415         "fluidsim",
416         "frameserver",
417         "freestyle",
418         "enum", "enums",
419         "gpencil",
420         "idcol",
421         "keyframe", "keyframes", "keyframing", "keyframed",
422         "metaball", "metaballs", "mball",
423         "metaelement", "metaelements",
424         "metastrip", "metastrips",
425         "movieclip",
426         "mpoly",
427         "mtex",
428         "nabla",
429         "navmesh",
430         "outliner",
431         "paintmap", "paintmaps",
432         "polygroup", "polygroups",
433         "poselib",
434         "pushpull",
435         "pyconstraint", "pyconstraints",
436         "qe",  # keys...
437         "shapekey", "shapekeys",
438         "shrinkfatten",
439         "shrinkwrap",
440         "softbody",
441         "stucci",
442         "sunsky",
443         "subsurf",
444         "tessface", "tessfaces",
445         "texface",
446         "timeline", "timelines",
447         "tosphere",
448         "uilist",
449         "vcol", "vcols",
450         "vgroup", "vgroups",
451         "vinterlace",
452         "wasd", "wasdqe",  # keys...
453         "wetmap", "wetmaps",
454         "wpaint",
455         "uvwarp",
456
457         # Algorithm names
458         "beckmann",
459         "catmull",
460         "catrom",
461         "chebychev",
462         "courant",
463         "hosek",
464         "kutta",
465         "lennard",
466         "mikktspace",
467         "minkowski",
468         "minnaert",
469         "musgrave",
470         "nayar",
471         "netravali",
472         "oren",
473         "preetham",
474         "prewitt",
475         "runge",
476         "sobol",
477         "verlet",
478         "wilkie",
479         "worley",
480
481         # Acronyms
482         "aa", "msaa",
483         "ao",
484         "api",
485         "asc", "cdl",
486         "ascii",
487         "atrac",
488         "bsdf",
489         "bssrdf",
490         "bw",
491         "ccd",
492         "cmd",
493         "cpus",
494         "ctrl",
495         "cw", "ccw",
496         "dev",
497         "djv",
498         "dpi",
499         "dvar",
500         "dx",
501         "eo",
502         "fh",
503         "fov",
504         "fft",
505         "futura",
506         "gfx",
507         "gl",
508         "glsl",
509         "gpl",
510         "gpu", "gpus",
511         "hc",
512         "hdc",
513         "hdr",
514         "hh", "mm", "ss", "ff",  # hh:mm:ss:ff timecode
515         "hsv", "hsva", "hsl",
516         "id",
517         "ior",
518         "itu",
519         "lhs",
520         "lmb", "mmb", "rmb",
521         "kb",
522         "mocap",
523         "msgid", "msgids",
524         "mux",
525         "ndof",
526         "ppc",
527         "precisa",
528         "px",
529         "qmc",
530         "rgb", "rgba",
531         "rhs",
532         "rv",
533         "sdl",
534         "sl",
535         "smpte",
536         "svn",
537         "ui",
538         "unix",
539         "vbo", "vbos",
540         "ycc", "ycca",
541         "yuv", "yuva",
542
543         # Blender acronyms
544         "bge",
545         "bli",
546         "bpy",
547         "bvh",
548         "dbvt",
549         "dop",  # BLI K-Dop BVH
550         "ik",
551         "nla",
552         "py",
553         "qbvh",
554         "rna",
555         "rvo",
556         "simd",
557         "sph",
558         "svbvh",
559
560         # Files types/formats
561         "avi",
562         "attrac",
563         "autocad",
564         "autodesk",
565         "bmp",
566         "btx",
567         "cineon",
568         "dpx",
569         "dxf",
570         "eps",
571         "exr",
572         "fbx",
573         "ffmpeg",
574         "flac",
575         "gzip",
576         "ico",
577         "jpg", "jpeg",
578         "json",
579         "matroska",
580         "mdd",
581         "mkv",
582         "mpeg", "mjpeg",
583         "mtl",
584         "ogg",
585         "openjpeg",
586         "osl",
587         "oso",
588         "piz",
589         "png",
590         "po",
591         "quicktime",
592         "rle",
593         "sgi",
594         "stl",
595         "svg",
596         "targa", "tga",
597         "tiff",
598         "theora",
599         "vorbis",
600         "wav",
601         "xiph",
602         "xml",
603         "xna",
604         "xvid",
605     }
606
607     _valid_before = "(?<=[\\s*'\"`])|(?<=[a-zA-Z][/-])|(?<=^)"
608     _valid_after = "(?=[\\s'\"`.!?,;:])|(?=[/-]\\s*[a-zA-Z])|(?=$)"
609     _valid_words = "(?:{})(?:(?:[A-Z]+[a-z]*)|[A-Z]*|[a-z]*)(?:{})".format(_valid_before, _valid_after)
610     _split_words = re.compile(_valid_words).findall
611
612     @classmethod
613     def split_words(cls, text):
614         return [w for w in cls._split_words(text) if w]
615
616     def __init__(self, settings, lang="en_US"):
617         self.settings = settings
618         self.dict_spelling = enchant.Dict(lang)
619         self.cache = set(self.uimsgs)
620
621         cache = self.settings.SPELL_CACHE
622         if cache and os.path.exists(cache):
623             with open(cache, 'rb') as f:
624                 self.cache |= set(pickle.load(f))
625
626     def __del__(self):
627         cache = self.settings.SPELL_CACHE
628         if cache and os.path.exists(cache):
629             with open(cache, 'wb') as f:
630                 pickle.dump(self.cache, f)
631
632     def check(self, txt):
633         ret = []
634
635         if txt in self.cache:
636             return ret
637
638         for w in self.split_words(txt):
639             w_lower = w.lower()
640             if w_lower in self.cache:
641                 continue
642             if not self.dict_spelling.check(w):
643                 ret.append((w, self.dict_spelling.suggest(w)))
644             else:
645                 self.cache.add(w_lower)
646
647         if not ret:
648             self.cache.add(txt)
649
650         return ret