From 581a2927977d4d13de0fdcbfdb3e43128f3ad017 Mon Sep 17 00:00:00 2001 From: ik1ne <3996272+ik1ne@users.noreply.github.com> Date: Sat, 19 Oct 2019 22:03:21 +0900 Subject: [PATCH] Add support for switch_lang for Korean. (#981) * switch korean letters to english * revised according to recent changes * Fix typo in tests/test_switch_lang.py * Add a test case for coverage * Change: Moved decomposing logic which changes command.script to get_new_command instead of match. * Fix: changed unicode characters to unicode string for python2 compatibility. * Fix: Modified to change request. @ik1ne @yangkyeongmo --- tests/rules/test_switch_lang.py | 12 ++++++--- thefuck/rules/switch_lang.py | 48 ++++++++++++++++++++++++++++++--- 2 files changed, 53 insertions(+), 7 deletions(-) diff --git a/tests/rules/test_switch_lang.py b/tests/rules/test_switch_lang.py index e2da837d..81634d17 100644 --- a/tests/rules/test_switch_lang.py +++ b/tests/rules/test_switch_lang.py @@ -1,6 +1,7 @@ # -*- encoding: utf-8 -*- import pytest + from thefuck.rules import switch_lang from thefuck.types import Command @@ -9,7 +10,8 @@ from thefuck.types import Command Command(u'фзе-пуе', 'command not found: фзе-пуе'), Command(u'λσ', 'command not found: λσ'), Command(u'שפא-עקא', 'command not found: שפא-עקא'), - Command(u'ךד', 'command not found: ךד')]) + Command(u'ךד', 'command not found: ךד'), + Command(u'녀애 ㅣㄴ', 'command not found: 녀애 ㅣㄴ')]) def test_match(command): assert switch_lang.match(command) @@ -19,7 +21,8 @@ def test_match(command): Command(u'ls', 'command not found: ls'), Command(u'агсл', 'command not found: агсл'), Command(u'фзе-пуе', 'some info'), - Command(u'שפא-עקא', 'some info')]) + Command(u'שפא-עקא', 'some info'), + Command(u'녀애 ㅣㄴ', 'some info')]) def test_not_match(command): assert not switch_lang.match(command) @@ -28,6 +31,9 @@ def test_not_match(command): (Command(u'фзе-пуе штыефдд мшь', ''), 'apt-get install vim'), (Command(u'λσ -λα', ''), 'ls -la'), (Command(u'שפא-עקא ןמדאשךך הןצ', ''), 'apt-get install vim'), - (Command(u'ךד -ךש', ''), 'ls -la')]) + (Command(u'ךד -ךש', ''), 'ls -la'), + (Command(u'멧-ㅎㄷㅅ ㅑㅜㄴㅅ미ㅣ 퍄ㅡ', ''), 'apt-get install vim'), + (Command(u'ㅣㄴ -ㅣㅁ', ''), 'ls -la'), + (Command(u'ㅔㅁㅅ촤', ''), 'patchk'), ]) def test_get_new_command(command, new_command): assert switch_lang.get_new_command(command) == new_command diff --git a/thefuck/rules/switch_lang.py b/thefuck/rules/switch_lang.py index d535ad88..6f8d7632 100644 --- a/thefuck/rules/switch_lang.py +++ b/thefuck/rules/switch_lang.py @@ -5,13 +5,14 @@ target_layout = '''qwertyuiop[]asdfghjkl;'zxcvbnm,./QWERTYUIOP{}ASDFGHJKL:"ZXCVB # any new keyboard layout must be appended greek = u''';ςερτυθιοπ[]ασδφγηξκλ΄ζχψωβνμ,./:΅ΕΡΤΥΘΙΟΠ{}ΑΣΔΦΓΗΞΚΛ¨"ΖΧΨΩΒΝΜ<>?''' +korean = u'''ㅂㅈㄷㄱㅅㅛㅕㅑㅐㅔ[]ㅁㄴㅇㄹㅎㅗㅓㅏㅣ;'ㅋㅌㅊㅍㅠㅜㅡ,./ㅃㅉㄸㄲㅆㅛㅕㅑㅒㅖ{}ㅁㄴㅇㄹㅎㅗㅓㅏㅣ:"ㅋㅌㅊㅍㅠㅜㅡ<>?''' source_layouts = [u'''йцукенгшщзхъфывапролджэячсмитьбю.ЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖЭЯЧСМИТЬБЮ,''', u'''йцукенгшщзхїфівапролджєячсмитьбю.ЙЦУКЕНГШЩЗХЇФІВАПРОЛДЖЄЯЧСМИТЬБЮ,''', u'''ضصثقفغعهخحجچشسیبلاتنمکگظطزرذدپو./ًٌٍَُِّْ][}{ؤئيإأآة»«:؛كٓژٰ‌ٔء><؟''', u'''/'קראטוןםפ][שדגכעיחלךף,זסבהנמצתץ.QWERTYUIOP{}ASDFGHJKL:"ZXCVBNM<>?''', - greek] - + greek, + korean] source_to_target = { greek: {u';': "q", u'ς': "w", u'ε': "e", u'ρ': "r", u'τ': "t", u'υ': "y", @@ -30,6 +31,19 @@ source_to_target = { u'Ώ': "V"}, } +'''Lists used for decomposing korean letters.''' +HEAD_LIST = [u'ㄱ', u'ㄲ', u'ㄴ', u'ㄷ', u'ㄸ', u'ㄹ', u'ㅁ', u'ㅂ', u'ㅃ', u'ㅅ', u'ㅆ', + u'ㅇ', u'ㅈ', u'ㅉ', u'ㅊ', u'ㅋ', u'ㅌ', u'ㅍ', u'ㅎ'] +BODY_LIST = [u'ㅏ', u'ㅐ', u'ㅑ', u'ㅒ', u'ㅓ', u'ㅔ', u'ㅕ', u'ㅖ', u'ㅗ', u'ㅘ', u'ㅙ', + u'ㅚ', u'ㅛ', u'ㅜ', u'ㅝ', u'ㅞ', u'ㅟ', u'ㅠ', u'ㅡ', u'ㅢ', u'ㅣ'] +TAIL_LIST = [u' ', u'ㄱ', u'ㄲ', u'ㄳ', u'ㄴ', u'ㄵ', u'ㄶ', u'ㄷ', u'ㄹ', u'ㄺ', u'ㄻ', + u'ㄼ', u'ㄽ', u'ㄾ', u'ㄿ', u'ㅀ', u'ㅁ', u'ㅂ', u'ㅄ', u'ㅅ', u'ㅆ', u'ㅇ', u'ㅈ', + u'ㅊ', u'ㅋ', u'ㅌ', u'ㅍ', u'ㅎ'] +DOUBLE_LIST = [u'ㅘ', u'ㅙ', u'ㅚ', u'ㅝ', u'ㅞ', u'ㅟ', u'ㅢ', u'ㄳ', u'ㄵ', u'ㄶ', u'ㄺ', + u'ㄻ', u'ㄼ', u'ㄽ', u'ㄾ', u'ㅀ', u'ㅄ'] +DOUBLE_MOD_LIST = [u'ㅗㅏ', u'ㅗㅐ', u'ㅗㅣ', u'ㅜㅓ', u'ㅜㅔ', u'ㅜㅣ', u'ㅡㅣ', u'ㄱㅅ', + u'ㄴㅈ', u'ㄴㅎ', u'ㄹㄱ', u'ㄹㅁ', u'ㄹㅂ', u'ㄹㅅ', u'ㄹㅌ', u'ㄹㅎ', u'ㅂㅅ'] + @memoize def _get_matched_layout(command): @@ -50,8 +64,7 @@ def _get_matched_layout(command): def _switch(ch, layout): if ch in layout: return target_layout[layout.index(ch)] - else: - return ch + return ch def _switch_command(command, layout): @@ -63,9 +76,33 @@ def _switch_command(command, layout): return ''.join(_switch(ch, layout) for ch in command.script) +def _decompose_korean(command): + def _change_double(ch): + if ch in DOUBLE_LIST: + return DOUBLE_MOD_LIST[DOUBLE_LIST.index(ch)] + return ch + + hg_str = u'' + for ch in command.script: + if u'가' <= ch <= u'힣': + ord_ch = ord(ch) - ord(u'가') + hd = ord_ch // 588 + bd = (ord_ch - 588 * hd) // 28 + tl = ord_ch - 588 * hd - 28 * bd + for ch in [HEAD_LIST[hd], BODY_LIST[bd], TAIL_LIST[tl]]: + if ch != ' ': + hg_str += _change_double(ch) + else: + hg_str += _change_double(ch) + return hg_str + + def match(command): if 'not found' not in command.output: return False + if any(u'ㄱ' <= ch <= u'ㅎ' or u'ㅏ' <= ch <= u'ㅣ' or u'가' <= ch <= u'힣' + for ch in command.script): + return True matched_layout = _get_matched_layout(command) return (matched_layout and @@ -73,5 +110,8 @@ def match(command): def get_new_command(command): + if any(u'ㄱ' <= ch <= u'ㅎ' or u'ㅏ' <= ch <= u'ㅣ' or u'가' <= ch <= u'힣' + for ch in command.script): + command.script = _decompose_korean(command) matched_layout = _get_matched_layout(command) return _switch_command(command, matched_layout)