1# vim:set et sts=4 sw=4:
2# -*- coding: utf-8 -*-
3#
4# ibus-anthy - The Anthy engine for IBus
5#
6# Copyright (c) 2007-2008 Peng Huang <shawn.p.huang@gmail.com>
7# Copyright (c) 2010-2017 Takao Fujiwara <takao.fujiwara1@gmail.com>
8# Copyright (c) 2007-2017 Red Hat, Inc.
9#
10# This program is free software; you can redistribute it and/or modify
11# it under the terms of the GNU General Public License as published by
12# the Free Software Foundation; either version 2 of the License, or
13# (at your option) any later version.
14#
15# This program is distributed in the hope that it will be useful,
16# but WITHOUT ANY WARRANTY; without even the implied warranty of
17# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18# GNU General Public License for more details.
19#
20# You should have received a copy of the GNU General Public License along
21# with this program; if not, write to the Free Software Foundation, Inc.,
22# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23
24import sys
25
26from tables import *
27import segment
28
29def romaji_correction_rule_get(k, d):
30    return ('ん', k[1:2]) if k[0:1] == 'n' and not k[1:2] in "aiueony'" else d
31
32class RomajiSegment(segment.Segment):
33    _prefs = None
34    _romaji_typing_rule_method = None
35    _latin_with_shift = True
36    _shift_mode = False
37
38    def __init__(self, enchars='', jachars='', shift=False, unshift=False):
39        if self._latin_with_shift:
40            # If Shift key is pressed, Latin mode.
41            # If Hiragana_Katakana key is pressed, Hiragana mode.
42            if shift:
43                self._shift_mode = True
44            if unshift:
45                self._shift_mode = False
46
47        enchars_orig = enchars
48        # Even if the chars are capital with CapsLock, Hiragana
49        # should be converted. E.g. 'SA'
50        enchars = enchars.lower()
51
52        if not jachars and not shift:
53            jachars = self.__get_romaji_typing_rule(enchars, None)
54            if jachars == None:
55                jachars = symbol_rule.get(enchars, '')
56        super(RomajiSegment, self).__init__(enchars_orig, jachars)
57
58    @classmethod
59    def INIT_ROMAJI_TYPING_RULE(cls, prefs):
60        cls._prefs = prefs
61        if prefs == None:
62            cls._romaji_typing_rule_method = None
63            return
64        method = prefs.get_value('romaji-typing-rule', 'method')
65        if method == None:
66            method = 'default'
67        cls._romaji_typing_rule_method = method
68        keymap = prefs.get_value('romaji-typing-rule', 'list')
69        if cls._romaji_typing_rule_method not in keymap.keys():
70            cls._romaji_typing_rule_method = None
71
72    @classmethod
73    def SET_LATIN_WITH_SHIFT(cls, latin_with_shift):
74        # Do not use IBus.Config in every conversion for the performance.
75        cls._latin_with_shift = latin_with_shift
76
77    def __get_romaji_typing_rule(self, enchars, retval=None):
78        prefs = self._prefs
79        value = None
80        method = self._romaji_typing_rule_method
81        if method != None:
82            # Need to send Unicode to typing_to_config_key instead of UTF-8
83            # not to separate U+A5
84            gkey = prefs.typing_to_config_key(enchars)
85            if gkey == '':
86                return None
87            keymap = prefs.get_value('romaji-typing-rule', 'list')[method]
88            value = keymap.get(gkey)
89            if value == '':
90                value = None
91            if value == None:
92                value = retval
93        else:
94            value = romaji_typing_rule_static.get(enchars, retval)
95        return value
96
97    def is_finished(self):
98        return self._jachars != ''
99
100    def append(self, enchar, shift=False, unshift=False):
101        if self.is_finished():
102            if enchar == '' and enchar == '\0':
103                return []
104            return [RomajiSegment(enchar)]
105
106        text_orig = self._enchars + enchar
107        text = text_orig.lower()
108
109        if self._latin_with_shift:
110            # If Shift key is pressed, Latin mode.
111            # If Hiragana_Katakana key is pressed, Hiragana mode.
112            if shift:
113                self._shift_mode = True
114            if unshift:
115                self._shift_mode = False
116            if self._shift_mode:
117                self._enchars = text_orig
118                return []
119
120        if shift:
121            self._enchars = text_orig
122            return []
123
124        jachars = self.__get_romaji_typing_rule(text, None)
125        if jachars == None:
126            jachars = symbol_rule.get(text, None)
127        if jachars:
128            self._enchars = text_orig
129            self._jachars = jachars
130            return []
131
132        jachars, c = romaji_double_consonat_typing_rule.get(text, (None, None))
133        if jachars:
134            self._enchars = text_orig[0]
135            self._jachars = jachars
136            return [RomajiSegment(c)]
137
138#        jachars, c = romaji_correction_rule.get(text, (None, None))
139        jachars, c = romaji_correction_rule_get(text, (None, None))
140        if jachars:
141            self._enchars = text_orig[0]
142            self._jachars = jachars
143            return [RomajiSegment(c)]
144
145        for i in range(-min(4, len(text)), 0):
146            enchars = text[i:]
147
148            jachars = self.__get_romaji_typing_rule(enchars, None)
149            if jachars == None:
150                jachars = symbol_rule.get(enchars, None)
151            if jachars:
152                jasegment = RomajiSegment(enchars, jachars)
153                self._enchars = text_orig[:i]
154                return [jasegment]
155
156            jachars, c = romaji_double_consonat_typing_rule.get(enchars, (None, None))
157            if jachars:
158                jasegment = RomajiSegment(enchars[:-len(c)], jachars)
159                self._enchars = text_orig[:i]
160                if c:
161                    return [jasegment, RomajiSegment(c)]
162                return [jasegment]
163
164#            jachars, c = romaji_correction_rule.get(enchars, (None, None))
165            jachars, c = romaji_correction_rule_get(enchars, (None, None))
166            if jachars:
167                jasegment = RomajiSegment(enchars[:-len(c)], jachars)
168                self._enchars = text_orig[:i]
169                if c:
170                    return [jasegment, RomajiSegment(c)]
171                return [jasegment]
172
173        self._enchars = text_orig
174        return []
175
176    def prepend(self, enchar, shift=False, unshift=False):
177        if enchar == '' or enchar == '\0':
178            return []
179
180        if self.is_finished():
181            return [RomajiSegment(enchar)]
182
183        text_orig  = enchar + self._enchars
184        text  = text_orig.lower()
185
186        if self._latin_with_shift:
187            if shift:
188                self._shift_mode = True
189            if unshift:
190                self._shift_mode = False
191            if self._shift_mode:
192                self._enchars = text_orig
193                return []
194
195        if shift:
196            self._enchars = text_orig
197            return []
198
199        jachars = self.__get_romaji_typing_rule(text, None)
200        if jachars == None:
201            jachars = symbol_rule.get(text, None)
202        if jachars:
203            self._enchars = text_orig
204            self._jachars = jachars
205            return []
206
207        jachars, c = romaji_double_consonat_typing_rule.get(text, (None, None))
208        if jachars:
209            self._enchars = c
210            return [RomajiSegment(text_orig[0], jachars)]
211
212#        jachars, c = romaji_correction_rule.get(text, (None, None))
213        jachars, c = romaji_correction_rule_get(text, (None, None))
214        if jachars:
215            self._enchars = c
216            return [RomajiSegment(text_orig[0], jachars)]
217
218        for i in range(min(4, len(text)), 0, -1):
219            enchars = text[:i]
220
221            jachars = self.__get_romaji_typing_rule(enchars, None)
222            if jachars == None:
223                jachars = symbol_rule.get(enchars, None)
224            if jachars:
225                jasegment = RomajiSegment(enchars, jachars)
226                self._enchars = text_orig[i:]
227                return [jasegment]
228
229            jachars, c = romaji_double_consonat_typing_rule.get(enchars, (None, None))
230            if jachars:
231                self._enchars = c + text_orig[i:]
232                return [RomajiSegment(enchars[:-len(c)], jachars)]
233
234#            jachars, c = romaji_correction_rule.get(enchars, (None, None))
235            jachars, c = romaji_correction_rule_get(enchars, (None, None))
236            if jachars:
237                self._enchars = c + text_orig[i:]
238                return [RomajiSegment(enchars[:-len(c)], jachars)]
239
240        self._enchars = text_orig
241        return []
242
243    def pop(self, index=-1):
244        if index == -1:
245            index = len(self._enchars) - 1
246        if index < 0 or index >= len(self._enchars):
247            raise IndexError('Out of bound')
248        if self.is_finished():
249            self._enchars = ''
250            self._jachars = ''
251        else:
252            enchars = list(self._enchars)
253            del enchars[index]
254            self._enchars = ''.join(enchars)
255            jachars = self.__get_romaji_typing_rule(self._enchars, None)
256            if jachars == None:
257                jachars = symbol_rule.get(self._enchars, '')
258            self._jachars = jachars
259
260
261