Hiroyuki Komatsu
komat****@users*****
2005年 2月 15日 (火) 20:17:36 JST
Index: prime/lib/session-japanese.rb diff -u /dev/null prime/lib/session-japanese.rb:1.1.2.1 --- /dev/null Tue Feb 15 20:17:35 2005 +++ prime/lib/session-japanese.rb Tue Feb 15 20:17:35 2005 @@ -0,0 +1,537 @@ +# session-japanese.rb: Session library for Japanese. +# $Id: session-japanese.rb,v 1.1.2.1 2005/02/15 11:17:35 komatsu Exp $ +# +# Copyright (C) 2005 Hiroyuki Komatsu <komat****@taiya*****> +# All rights reserved. +# This is free software with ABSOLUTELY NO WARRANTY. +# +# You can redistribute it and/or modify it under the terms of +# the GNU General Public License version 2. + +require 'prime/session' +require 'prime/composer' +require 'prime/prime-japanese' +require 'prime/prime-mixed' + +require 'prime/engine/engine-basic' +require 'prime/engine/engine-userdict2' +require 'prime/engine/engine-personaldict' +require 'prime/engine/engine-alphabet' +require 'prime/engine/engine-number' + +class PrimeSessionJapanese < PrimeSession + include PrimeComposer + include PrimeJapanese + include PrimeMixed + + def initialize () + name = "Japanese" + engine_classes = [ + :PrimeEngineBasic, + :PrimeEngineUserdict2, + :PrimeEnginePersonalDict, + :PrimeEngineAlphabet, + :PrimeEngineNumber, + ] + super(name, engine_classes) + @language = "Japanese" + initialize_prime_japanese() + end + + def initialize_composer () + composer = SuikyoComposer.new() + composer.set_table(PRIME_ENV['suikyo_tables']) + composer.set_reverse_table(PRIME_ENV['suikyo_reverse_tables']) + + ## Setting hybrid_typing. + if PRIME_ENV['hybrid_typing'].nil? then + if PRIME_ENV['typing_method'] == 'romaji' then + PRIME_ENV['hybrid_typing'] = true + composer.hybrid_typing = true + end + else + composer.hybrid_typing = PRIME_ENV['hybrid_typing'] + end + + ## Setting period and comma in Japanese. + period = PRIME_ENV['style_japanese_period'] + comma = PRIME_ENV['style_japanese_comma'] + case PRIME_ENV['typing_method'] + when "romaji" then + composer.set_table_entry('.', period) + composer.set_table_entry(',', comma) + composer.set_reverse_table_entry(period, '.') + composer.set_reverse_table_entry(comma, ',') + when "kana" then + composer.set_table_entry('>', period) + composer.set_table_entry('<', comma) + composer.set_reverse_table_entry(period, '>') + composer.set_reverse_table_entry(comma, '<') + when "tcode" then + for char in 'A'..'Z' do + composer.set_table_entry(char, char) + composer.set_reverse_table_entry(char, char) + end + end + + return composer + end + + def set_conversions (conversions) + @conversions = conversions + end + + def set_selection (index_no) + @conversions.set_conversion_index(index_no) + return @conversions[index_no] + end + def get_selection () + retur****@conve*****_conversion() + end + + def set_context (context) + @context = context + end + def get_context () + return @context + end + + ## + ## Context methods + ## + def context_reset () + set_context("") + end + + def context_set_previous_segment (segment) + context_set_previous_word( segment.get_base() ) + end + + def context_set_previous_word (word) + set_context(word) + end + + ## + ## Conversion methods + ## + + ## This returns a PrimeConversionList. + def conv_convert (method = nil) + if PRIME_ENV['typing_method'] == 'tcode' or + PRIME_ENV['typing_method'] == 'handwrite' then + conversions_expansion = convert_expansion()[0,3] + ## FIXME: Delete the magic number. + ## FIXME: (2004-12-22) <Hiro> + conversions_expansion.add_score( 50000 ) + conversions_mixed = convert_mixed() + conversions_japanese = convert_japanese() + conversions_overall = convert_overall() + + conversions = PrimeConversionList::merge( conversions_expansion, + conversions_japanese, + conversions_overall ) + else + conversions_compact = convert_compact() + ## FIXME: Delete the magic number. + ## FIXME: (2004-12-22) <Hiro> + conversions_compact.add_score( 50000 ) + conversions_japanese = convert_japanese() + conversions_overall = convert_overall() + + conversions = PrimeConversionList::merge( conversions_compact, + conversions_japanese, + conversions_overall ) + end + + set_conversions(conversions) + return conversions + end + + def conv_predict (method = nil) + if PRIME_ENV['typing_method'] == 'tcode' or + PRIME_ENV['typing_method'] == 'handwrite' then + conversions = PrimeConversionList.new( convert_expansion()[0,3] ) + else + conversions = convert_compact() + end + + set_conversions(conversions) + return conversions + end + + def conv_select (index) + conversion = set_selection(index) + return conversion + end + + def conv_commit () + conversion = get_selection() + + ## Commit the current conversion + conversion.segments.each { | segment | + learn_segment( segment, get_context() ) + + context_reset() + context_set_previous_segment(segment) + } + commited_string = conversion.get_literal() + + ## Reset the conversion. + edit_erase() + + return commited_string + end + + def learn_segment (segment, context) + base = segment.get_base() + base_reading = segment.get_base_reading() + pos = segment.get_pos() + adjunct = segment.get_adjunct() + rest = "" + + @engines.command(:learn_word, + base_reading, base, pos, context, adjunct, rest) + end + + def _adhoc_wordlist_to_conversionlist (wordlist) + conversion_list = [] + wordlist.length.times { | index | + word = wordlist[index] + reading = word.to_text_pron() + + segment = PrimeSegment.new(reading) + segment.set_candidates(wordlist, index) + + conversion_list.push( PrimeConversion.new( [segment], word.score ) ) + } + return PrimeConversionList.new(conversion_list) + end + + ## + ## Modification methods + ## + def modify_start () + conversion = get_selection() + conversion.position_right_edge() + end + + def modify_select (index_no) + conversion = get_selection() + conversion.candidate_select(index_no) + end + + def modify_commit () + end + + def modify_reconvert () + conversion = get_selection() + segment = conversion.get_segment() + + segment_reconvert(segment) + + return modify_get_segment() + end + + def modify_get_segment () + conversion = get_selection() + return conversion.get_segment() + end + + def modify_get_conversion () + conversion = get_selection() + return conversion.get_conversion() + end + + def modify_cursor_left () + conversion = get_selection() + conversion.position_left() + end + def modify_cursor_right () + conversion = get_selection() + conversion.position_right() + end + def modify_cursor_left_edge () + conversion = get_selection() + conversion.position_left_edge() + end + def modify_cursor_right_edge () + conversion = get_selection() + conversion.position_right_edge() + end + def modify_cursor_expand () + conversion = get_selection() + conversion.segment_expand() + end + def modify_cursor_shrink () + conversion = get_selection() + conversion.segment_shrink() + end + + private + ## This is a wrapper for convert_*. This converts query to + ## a PrimeConversionList insted of PrimeWordList and returns it. + def convert (query) + query.input.uniq!() + words_list =****@engin*****(:search, query) + wordlist = PrimeWordList::merge(words_list) + + PrimeWordList::attach_prefix(@context, wordlist) + return _adhoc_wordlist_to_conversionlist( wordlist ) + end + private :convert + + def convert_prefix () + # 「よ→予測」 + context = get_context() + expansion =****@compo*****_get_expansion() + query = PrimeQuery.new(expansion, nil, :prefix, context) + return convert(query) + end + + def convert_exact () + # 「よそく→予測」 + context = get_context() + conversion =****@compo*****_get_conversion() + query = PrimeQuery.new(conversion, nil, :exact, context) + return convert(query) + end + + def convert_expansion () + # 「予→予測」 + context = get_context() + expansion =****@compo*****_get_expansion() + query = PrimeQuery.new(expansion, nil, :literal_prefix, context) + return convert(query) + end + + def convert_overall () + # 「1+1=→2」, 「aiueo→アイウエオ」 + raw_input =****@compo*****_get_raw_input() + query = PrimeQuery.new(raw_input, nil, :overall) + return convert(query) + end + + def convert_compact () + conversion_prefix = convert_prefix().first() + + ## If the result of search_prefix is empty, this method stops the following + ## search_japanese_uniclause for the quickness. + if conversion_prefix.nil?() then + return PrimeConversionList.new() + end + + ## If the result of convert_japanese_uniclause exists and the score of it + ## is greater than the result of convert_prefix, the return conversion + ## becomes the convert_japanese_uniclause's one. + conversion_japanese = convert_japanese_uniclause().first() + if conversion_japanese.nil?() then + conversion = conversion_prefix + elsif conversion_japanese.score < conversion_prefix.score then + conversion = conversion_prefix + else ## conversion_japanese.score >= conversion_prefix.score + conversion = conversion_japanese + end + + ## Predict a next segment of the conversion. + next_segment = predict_next_segment( conversion ) + if next_segment.nil? then + return PrimeConversionList.new( [conversion] ) + end + + conversion2 = conversion.dup() + conversion2.segment_insert(next_segment) + return PrimeConversionList.new( [conversion, conversion2] ) + end + + ## This predicts candidate words as a next word for the specified conversion + ## data. For example when the specified conversion means "どうもありがとう", + ## one of the results would contain "ございます". + def predict_next_segment (conversion) + if conversion.nil? then + return nil + end + + ## The current context is just the previous word. + context = conversion.get_literal() + + ## If the last character of the specified conversion is one of stop_words, + ## This method stops its prediction. (EXPERIMENTAL) + stop_words = \ + [ PRIME_ENV['style_japanese_period'], + PRIME_ENV['style_japanese_comma'] ] + if context =~ /(#{stop_words.join('|')})$/ then + return nil + end + + query = PrimeQuery.new([""], nil, :context, context) + next_words = search(query) + if next_words.empty? then + return nil + end + + ## Create a PrimeSegment from the first value of a PrimeWord. + next_words = next_words[0,1] + + next_word = next_words.first + next_word.prefix = Prime::get_prefix(context, next_word.literal) + + reading = next_word.to_text_pron() + base_reading = "" + pos = nil + adjunct = "" + pos_adjunct = nil + + next_segment = PrimeSegment.new(reading, base_reading, pos, + adjunct, pos_adjunct, context) + next_segment.set_candidates(next_words, 0) + return next_segment + end + private :predict_next_segment + + ## This returns a PrimeConversionList. + def convert_japanese () + segments_list = convert_japanese_process_segments_list(@composer) + conversions = [] + + segments_list.each { | segments | + if segments.length == 1 then + conversions += convert_from_segment( segments.first() ) + else + segments.each { | segment | + query = PrimeQuery.new( [segment.base_reading], segment.pos ) + words = search(query) + words.each { | word | + word.conjugation = segment.adjunct + word.conjugation_pos = segment.pos_adjunct + } + index = (segment.pos == nil) ? -1 : 0 + segment.set_candidates(words, index) + } + score = convert_japanese_get_score(segments) + conversions.push( PrimeConversion.new(segments, score) ) + end + } + return PrimeConversionList.new( conversions ) + end + + ## This returns a PrimeWordList. + ## FIXME: Change the method name. + def convert_japanese_uniclause () + segments_list = convert_japanese_process_segments_list(@composer, 1) + conversions = PrimeConversionList.new() + + segments_list.each { | segments | # The lengh of segments must be 1. + conversions += convert_from_segment( segments.first() ) + } + return conversions + end + + ## This converts from the specified segment to convertions. + ## FIXME: Chage the function name. + ## FIXME: (2004-12-19) <Hiro>. + def convert_from_segment (segment) + conversions = PrimeConversionList.new() + query = PrimeQuery.new( [segment.base_reading], segment.pos ) + words = search(query) + + words.length.times { | index | + word = words[index] + word.conjugation = segment.adjunct + word.conjugation_pos = segment.pos_adjunct + + new_segment = segment.dup() + new_segment.set_candidates(words, index) + conversions.push( PrimeConversion.new( [new_segment], word.score ) ) + } + return conversions + end + private :convert_from_segment + + def segment_reconvert (segment, context = nil) + reading = segment.reading + words1 = search_raw(reading) + words2 = search_overall(reading) + words3 = search_japanese_uniclause(reading) +# words = PrimeWordList::merge_by_literal(context, words1, words2, words3) + + candidates = segment.get_candidates() + candidate_index = segment.get_candidate_index() + + candidates = PrimeWordList::merge2([candidates], [words1, words2, words3]) + segment.set_candidates( candidates, candidate_index ) + end + + def convert_japanese_process_segments_list (composer, threshold = 4) + string = composer.edit_get_surface_string() + (depth, segments_list) = guess_clauses_internal(string, 1, nil, threshold) + + conversions = [] + min_length = depth + + segments_list.each { | segments | + if segments.length < min_length then + conversions = [] + min_length = segments.length + elsif segments.length == min_length then + prime_segments = [] + segments.each { | (base_reading, pos, adjunct, pos_adjunct, engines) | + prime_segment = PrimeSegment.new(base_reading + adjunct, + base_reading, pos, + adjunct, pos_adjunct) + prime_segments.push(prime_segment) + } + conversions.push(prime_segments) + end + } + return conversions + end + private :convert_japanese_process_segments_list + + def convert_japanese_get_score (segments) + segment = segments[0] + pos = segment.pos + literal = segment.get_literal() + score = segment.get_score() + + segments[1..-1].each { | segment2 | + pos2 = segment2.pos + literal2 = segment2.get_literal() + score2 = segment2.get_score() + if pos2.nil? then + cost = 0.9 ** literal2.length + else + cost = _get_connection_cost(pos, literal, pos2, literal2) + end + connection_key = [pos, pos2].join("\t") + pos = (@pos_connection_pos[connection_key] or pos2) + + score = (Math::sqrt(score * score2) * cost).to_i + } + return score + end + private :convert_japanese_get_score + + #### ------------------------------------------------------------ + ## FIXME: revise the following mehods. + ## FIXME: (2005-01-31) <Hiroyuki Komatsu> + def search (query) + query.input.uniq!() + words_list =****@engin*****(:search, query) + return PrimeWordList::merge(words_list) + end + + def search_raw (string) + ## FIXME: This method is an ad-hoc routine for search_japanese. + ## FIXME: <komat****@taiya*****> (2004-02-28) + query = PrimeQuery.new([string], nil, :exact, @context) + words = search(query) + return words + end + + def search_overall (string) + # 「1+1=→2」, 「aiueo→アイウエオ」 + query = PrimeQuery.new([string], nil, :overall) + words_overall = search(query) + return words_overall + end +end Index: prime/lib/session-english.rb diff -u /dev/null prime/lib/session-english.rb:1.1.2.1 --- /dev/null Tue Feb 15 20:17:35 2005 +++ prime/lib/session-english.rb Tue Feb 15 20:17:35 2005 @@ -0,0 +1,229 @@ +# session-english.rb: Session library for English. +# $Id: session-english.rb,v 1.1.2.1 2005/02/15 11:17:35 komatsu Exp $ +# +# Copyright (C) 2005 Hiroyuki Komatsu <komat****@taiya*****> +# All rights reserved. +# This is free software with ABSOLUTELY NO WARRANTY. +# +# You can redistribute it and/or modify it under the terms of +# the GNU General Public License version 2. + +require 'prime/session' +require 'prime/composer' + +require 'prime/engine/engine-english' +require 'prime/engine/engine-userdict2-en' +require 'prime/engine/engine-personaldict' +require 'prime/engine/engine-alphabet' +require 'prime/engine/engine-number' + +class PrimeSessionEnglish < PrimeSession + include PrimeComposer + + def initialize () + name = "English" + engine_classes = [ + :PrimeEngineEnglish, + :PrimeEngineUserdict2English, + :PrimeEnginePersonalDict, + :PrimeEngineAlphabet, + :PrimeEngineNumber, + ] + super(name, engine_classes) + @language = "English" + end + + def set_conversions (conversions) + @conversions = conversions + end + + def set_selection (index_no) + @conversions.set_conversion_index(index_no) + return @conversions[index_no] + end + def get_selection () + retur****@conve*****_conversion() + end + + def set_context (context) + @context = context + end + def get_context () + return @context + end + + ## + ## Context methods + ## + def context_reset () + set_context("") + end + + def context_set_previous_segment (segment) + context_set_previous_word( segment.get_base() ) + end + + def context_set_previous_word (word) + set_context(word) + end + + + ## + ## Conversion methods + ## + + ## This returns a PrimeConversionList. + def conv_convert (method = nil) + conversions_compact = convert_compact() + ## FIXME: Delete the magic number. + ## FIXME: (2004-12-22) <Hiro> + conversions_compact.add_score( 50000 ) + conversions_prefix = convert_prefix() + + conversions = PrimeConversionList::merge( conversions_compact, + conversions_prefix ) + set_conversions(conversions) + return conversions + end + + def conv_predict (method = nil) + conversions = convert_compact() + set_conversions(conversions) + return conversions + end + + def conv_select (index) + conversion = set_selection(index) + return conversion + end + + def conv_commit () + conversion = get_selection() + + ## Commit the current conversion + conversion.segments.each { | segment | + learn_segment( segment, get_context() ) + + context_reset() + context_set_previous_segment(segment) + } + commited_string = conversion.get_literal() + + ## Reset the conversion. + edit_erase() + + return commited_string + end + + def learn_segment (segment, context) + base = segment.get_base() + base_reading = segment.get_base_reading() + pos = segment.get_pos() + adjunct = segment.get_adjunct() + rest = "" + + @engines.command(:learn_word, + base_reading, base, pos, context, adjunct, rest) + end + + def _adhoc_wordlist_to_conversionlist (wordlist) + conversion_list = [] + wordlist.length.times { | index | + word = wordlist[index] + reading = word.to_text_pron() + + segment = PrimeSegment.new(reading) + segment.set_candidates(wordlist, index) + + conversion_list.push( PrimeConversion.new( [segment], word.score ) ) + } + return PrimeConversionList.new(conversion_list) + end + + private + ## This is a wrapper for convert_*. This converts query to + ## a PrimeConversionList insted of PrimeWordList and returns it. + def convert (query) + query.input.uniq!() + words_list =****@engin*****(:search, query) + wordlist = PrimeWordList::merge(words_list) + + PrimeWordList::attach_prefix(@context, wordlist) + return _adhoc_wordlist_to_conversionlist( wordlist ) + end + private :convert + + def convert_compact () + conversion = convert_prefix().first() + + ## If the result of search_prefix is empty, this method stops the following + ## search_japanese_uniclause for the quickness. + if conversion.nil?() then + return PrimeConversionList.new() + end + + ## Predict a next segment of the conversion. + next_segment = predict_next_segment( conversion ) + if next_segment.nil? then + return PrimeConversionList.new( [conversion] ) + end + + conversion2 = conversion.dup() + conversion2.segment_insert(next_segment) + return PrimeConversionList.new( [conversion, conversion2] ) + end + + def convert_prefix () + # 「よ→予測」 + context = get_context() + expansion =****@compo*****_get_expansion() + query = PrimeQuery.new(expansion, nil, :prefix, context) + return convert(query) + end + + ## This predicts candidate words as a next word for the specified conversion + ## data. For example when the specified conversion means "looking", + ## one of the results would contain "forward". + def predict_next_segment (conversion) + if conversion.nil? then + return nil + end + + ## The current context is just the previous word. + context = conversion.get_literal() + + query = PrimeQuery.new([""], nil, :context, context) + next_words = search(query) + if next_words.empty? then + return nil + end + + ## Create a PrimeSegment from the first value of a PrimeWord. + next_words = next_words[0,1] + + next_word = next_words.first + next_word.prefix = Prime::get_prefix(context, next_word.literal) + + reading = next_word.to_text_pron() + base_reading = "" + pos = nil + adjunct = "" + pos_adjunct = nil + + next_segment = PrimeSegment.new(reading, base_reading, pos, + adjunct, pos_adjunct, context) + next_segment.set_candidates(next_words, 0) + return next_segment + end + private :predict_next_segment + + #### ------------------------------------------------------------ + ## FIXME: revise the following mehods. + ## FIXME: (2005-01-31) <Hiroyuki Komatsu> + def search (query) + query.input.uniq!() + words_list =****@engin*****(:search, query) + return PrimeWordList::merge(words_list) + end +end + Index: prime/lib/prime08.rb diff -u prime/lib/prime08.rb:1.1.2.2 prime/lib/prime08.rb:1.1.2.3 --- prime/lib/prime08.rb:1.1.2.2 Tue Feb 1 08:37:44 2005 +++ prime/lib/prime08.rb Tue Feb 15 20:17:35 2005 @@ -1,5 +1,5 @@ # prime08.rb: Module for the PRIME 0.8 protocol -# $Id: prime08.rb,v 1.1.2.2 2005/01/31 23:37:44 komatsu Exp $ +# $Id: prime08.rb,v 1.1.2.3 2005/02/15 11:17:35 komatsu Exp $ # # Copyright (C) 2005 Hiroyuki Komatsu <komat****@taiya*****> # All rights reserved. @@ -87,4 +87,7 @@ def lookup_expansion (string) return @session_prime08.lookup_expansion(string) end + def lookup_mixed (string) + return @session_prime08.lookup_mixed(string) + end end Index: prime/lib/prime-mixed.rb diff -u prime/lib/prime-mixed.rb:1.2.4.2 prime/lib/prime-mixed.rb:1.2.4.3 --- prime/lib/prime-mixed.rb:1.2.4.2 Tue Dec 14 17:16:31 2004 +++ prime/lib/prime-mixed.rb Tue Feb 15 20:17:35 2005 @@ -1,5 +1,5 @@ # prime/prime-mixed.rb -# $Id: prime-mixed.rb,v 1.2.4.2 2004/12/14 08:16:31 komatsu Exp $ +# $Id: prime-mixed.rb,v 1.2.4.3 2005/02/15 11:17:35 komatsu Exp $ # # Copyright (C) 2004 Hiroyuki Komatsu <komat****@taiya*****> # All rights reserved. @@ -10,13 +10,22 @@ # module PrimeMixed - def initialize_prime_mixed () - @prime_mixed_bigram = Hash.new(0) - filename = "/tmp/bigram-dict" - open(filename).each {|line| - (prev_char, char, score) = line.split("\t") - @prime_mixed_bigram[prev_char + "\t" + char] = score - } +# def initialize_prime_mixed () +# @prime_mixed_bigram = Hash.new(0) +# filename = "/tmp/bigram-dict" +# open(filename).each {|line| +# (prev_char, char, score) = line.split("\t") +# @prime_mixed_bigram[prev_char + "\t" + char] = score +# } +# end + + def convert_mixed () + context = get_context() + conversion =****@compo*****_get_surface_string() + data_list = process_data(conversion) + results = lookup_mixed_concat_data_list(data_list) + wordlist = PrimeWordList::merge_with_label(context, results) + return _adhoc_wordlist_to_conversionlist( wordlist ) end def lookup_mixed (string, max = 10) Index: prime/lib/composer.rb diff -u /dev/null prime/lib/composer.rb:1.1.2.1 --- /dev/null Tue Feb 15 20:17:35 2005 +++ prime/lib/composer.rb Tue Feb 15 20:17:35 2005 @@ -0,0 +1,108 @@ +# composer.rb: Module of composition for PrimeSession +# $Id: composer.rb,v 1.1.2.1 2005/02/15 11:17:35 komatsu Exp $ +# +# Copyright (C) 2005 Hiroyuki Komatsu <komat****@taiya*****> +# All rights reserved. +# This is free software with ABSOLUTELY NO WARRANTY. +# +# You can redistribute it and/or modify it under the terms of +# the GNU General Public License version 2. + +module PrimeComposer + ## + ## Composition methods + ## + def edit_insert (string) + @composer.edit_insert(string) + return true + end + def edit_delete () + @composer.edit_delete() + return true + end + def edit_backspace () + @composer.edit_backspace() + return true + end + def edit_erase () + @composer.edit_erase() + if PRIME_ENV['hybrid_typing'] then + @composer.set_mode_hybrid() + end + return true + end + def edit_undo () + @composer.undo() + return true + end + def edit_cursor_right () + @composer.cursor_right() + return true + end + def edit_cursor_left () + @composer.cursor_left() + return true + end + def edit_cursor_right_edge () + @composer.cursor_right_edge() + return true + end + def edit_cursor_left_edge () + @composer.cursor_left_edge() + return true + end + + ## This returns a list of the preediting string divided by the cursor + ## position. + def edit_get_preedition () + retur****@compo*****_get_preediting_string() + end + + def edit_get_query_string () + retur****@compo*****_get_query_string() + end + + def edit_set_mode (mode) + case mode + when "hybrid" then # Original + @composer.set_mode_hybrid() + when "default" then # F6 + @composer.set_mode_default() + when "katakana" then # F7 + @composer.set_mode_katakana() + when "half_katakana" then # F8 + @composer.set_mode_half_katakana() + when "wide_ascii" then # F9 + @composer.set_mode_wide_ascii() + when "raw" then # F10 + @composer.set_mode_raw() + else + return false + end + return true + end + + def edit_commit () + reading = edit_get_preedition().join() + + ## Commit the current conversion + base = reading + base_reading = reading + pos = nil + context = get_context() + adjunct = "" + rest = "" + + @engines.command(:learn_word, + base_reading, base, pos, context, adjunct, rest) + + ## Set next context + context_reset() + context_set_previous_word(reading) + + ## Reset the conversion. + edit_erase() + + return reading + end +end