Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

カンマとピリオド入力時の句読点の設定を追加 #248

Merged
merged 6 commits into from
Nov 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions macSKK.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@
CEA78FAE2961BA1D00B67E25 /* String+TransformTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEA78FAD2961BA1D00B67E25 /* String+TransformTests.swift */; };
CEA78FB02964209B00B67E25 /* UserDict.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEA78FAF2964209B00B67E25 /* UserDict.swift */; };
CEA78FB229646CA100B67E25 /* UserDictTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEA78FB129646CA100B67E25 /* UserDictTests.swift */; };
CEAC95572CF34E7700CD6D55 /* Punctuation.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEAC95562CF34E7700CD6D55 /* Punctuation.swift */; };
CEAC95592CF34F4100CD6D55 /* PunctuationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEAC95582CF34F4100CD6D55 /* PunctuationTests.swift */; };
CEADA44B2B025A0F0026E2BD /* Entry.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEADA44A2B025A0F0026E2BD /* Entry.swift */; };
CEADA44D2B025A8A0026E2BD /* EntryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEADA44C2B025A8A0026E2BD /* EntryTests.swift */; };
CEADA44F2B1357090026E2BD /* GeneralView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEADA44E2B1357090026E2BD /* GeneralView.swift */; };
Expand Down Expand Up @@ -255,6 +257,8 @@
CEA78FAD2961BA1D00B67E25 /* String+TransformTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+TransformTests.swift"; sourceTree = "<group>"; };
CEA78FAF2964209B00B67E25 /* UserDict.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDict.swift; sourceTree = "<group>"; };
CEA78FB129646CA100B67E25 /* UserDictTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDictTests.swift; sourceTree = "<group>"; };
CEAC95562CF34E7700CD6D55 /* Punctuation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Punctuation.swift; sourceTree = "<group>"; };
CEAC95582CF34F4100CD6D55 /* PunctuationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PunctuationTests.swift; sourceTree = "<group>"; };
CEADA44A2B025A0F0026E2BD /* Entry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Entry.swift; sourceTree = "<group>"; };
CEADA44C2B025A8A0026E2BD /* EntryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EntryTests.swift; sourceTree = "<group>"; };
CEADA44E2B1357090026E2BD /* GeneralView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeneralView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -414,6 +418,7 @@
CEADA44A2B025A0F0026E2BD /* Entry.swift */,
CE4CB5CB2AD557D90046FA34 /* NumberEntry.swift */,
CE84A3E6295DA4DA009394C4 /* Romaji.swift */,
CEAC95562CF34E7700CD6D55 /* Punctuation.swift */,
4B8E87D32CE05C3F004E7461 /* CurrentInput.swift */,
4B8E87D52CE05D0A004E7461 /* Key.swift */,
CE11C7BE2BE47D9800A35F3D /* KeyBinding.swift */,
Expand Down Expand Up @@ -477,6 +482,7 @@
CED1CA1D2BAFBE0600C32AE3 /* SKKServDictTests.swift */,
CEADA44C2B025A8A0026E2BD /* EntryTests.swift */,
CE84A3E8295DA504009394C4 /* RomajiTests.swift */,
CEAC95582CF34F4100CD6D55 /* PunctuationTests.swift */,
4B8E87D72CE0689D004E7461 /* CurrentInputTests.swift */,
CE118EE42CE0B4DB00A7C300 /* KeyTests.swift */,
CE2F3B122C030C9A00CE342B /* KeyBindingTests.swift */,
Expand Down Expand Up @@ -817,6 +823,7 @@
CED987412BB953E7001B40F9 /* Data+EucJis2004.swift in Sources */,
CE485A882A8FA195008271EF /* Release+UNNotification.swift in Sources */,
CED7CA3A2A839505004EF988 /* FetchUpdateServiceProtocol.swift in Sources */,
CEAC95572CF34E7700CD6D55 /* Punctuation.swift in Sources */,
CEA78FB02964209B00B67E25 /* UserDict.swift in Sources */,
CEF08257296D8CBD00646366 /* CandidatesPanel.swift in Sources */,
CEADA44B2B025A0F0026E2BD /* Entry.swift in Sources */,
Expand Down Expand Up @@ -863,6 +870,7 @@
CE496C952B440BBD001C623C /* Data+EucJis2004Tests.swift in Sources */,
CEE2D9792A99FEC700A4CD76 /* CandidateTest.swift in Sources */,
CEF0823629685C0800646366 /* StateTests.swift in Sources */,
CEAC95592CF34F4100CD6D55 /* PunctuationTests.swift in Sources */,
CED7CA3E2A8397E4004EF988 /* UpdateCheckerTests.swift in Sources */,
CE8DFE092CBEAA2900A24230 /* Character+AdditionsTests.swift in Sources */,
CE2F3B132C030C9A00CE342B /* KeyBindingTests.swift in Sources */,
Expand Down
2 changes: 2 additions & 0 deletions macSKK/Global.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ import Combine
static var systemDict: SystemDict.Kind = .daijirin
/// 変換候補選択中のバックスペースの挙動
static var selectingBackspace: SelectingBackspace = .default
/// カンマかピリオドを入力したときに入力する句読点の設定
static var punctuation: Punctuation = .default
/// 現在のモードを表示するパネル
private let inputModePanel: InputModePanel
/// 変換候補を表示するパネル
Expand Down
101 changes: 101 additions & 0 deletions macSKK/Punctuation.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// SPDX-License-Identifier: GPL-3.0-or-later

import Foundation

/**
* カンマとピリオドを入力したときに入力される句読点の設定.
* ローマ字かな変換ルールを上書きすることが可能。
*/
struct Punctuation {
enum Comma: Int, CaseIterable, Identifiable {
typealias ID = Int
var id: ID { rawValue }
/// ローマ字かな変換ルールをそのまま適用する
case `default` = 0
/// "、" を入力する
case ten = 1
/// "," (全角カンマ) を入力する
case comma = 2

init?(rawValue: Int) {
switch rawValue & 3 {
case 0:
self = .default
case 1:
self = .ten
case 2:
self = .comma
default:
return nil
}
}

var description: String {
switch self {
case .default:
return String(localized: "Follow Romaji-Kana Rule")
case .ten:
return String(format: String(localized: "EnterKey"), "、")
case .comma:
return String(format: String(localized: "EnterKey"), ",")
}
}
}

enum Period: Int, CaseIterable, Identifiable {
typealias ID = Int
var id: ID { rawValue }
/// ローマ字かな変換ルールをそのまま適用する
case `default` = 0
/// "。" を入力する
case maru = 256
/// "." (全角ピリオド) を入力する
case period = 512

init?(rawValue: Int) {
switch rawValue & 768 {
case 0:
self = .default
case 256:
self = .maru
case 512:
self = .period
default:
return nil
}
}

var description: String {
switch self {
case .default:
return String(localized: "Follow Romaji-Kana Rule")
case .maru:
return String(format: String(localized: "EnterKey"), "。")
case .period:
return String(format: String(localized: "EnterKey"), ".")
}
}
}

let comma: Comma
let period: Period

static let `default`: Self = .init(comma: .default, period: .default)

init(comma: Punctuation.Comma, period: Punctuation.Period) {
self.comma = comma
self.period = period
}

init?(rawValue: Int) {
guard let comma = Comma(rawValue: rawValue), let period = Period(rawValue: rawValue) else {
return nil
}
self.comma = comma
self.period = period
}

var rawValue: Int {
comma.rawValue | period.rawValue
}
}
24 changes: 20 additions & 4 deletions macSKK/Romaji.swift
Original file line number Diff line number Diff line change
Expand Up @@ -269,18 +269,34 @@ struct Romaji: Equatable, Sendable {
* - "kt" のように連続できない子音が連続したinputの場合は"k"を捨てて"t"をinput引数としたときのconvertの結果を返す
* - "kya" のように確定した文字が複数の場合がありえる
* - "aiueo" のように複数の確定が可能な場合は最初に確定できた文字だけを確定文字として返し、残りは(確定可能だが)inputとして返す
* - ",", "." は"、", "。"にする (将来設定で切り変えられるようにするかも)
* - ",", "." は引数 `comma`, `period` に従って変換する
* - "1" のように非ローマ字文字列を受け取った場合は未定義とする (呼び出し側で処理する予定だけどここで処理するかも)
*/
func convert(_ input: String) -> ConvertedMoji {
if let moji = table[input] {
func convert(_ input: String, punctuation: Punctuation) -> ConvertedMoji {
if input == "," && punctuation.comma != .default {
if case .ten = punctuation.comma {
return ConvertedMoji(input: "", kakutei: Romaji.Moji(firstRomaji: ",", kana: "、"))
} else if case .comma = punctuation.comma {
return ConvertedMoji(input: "", kakutei: Romaji.Moji(firstRomaji: ",", kana: ","))
} else {
fatalError()
}
} else if input == "." && punctuation.period != .default {
if case .maru = punctuation.period {
return ConvertedMoji(input: "", kakutei: Romaji.Moji(firstRomaji: ".", kana: "。"))
} else if case .period = punctuation.period {
return ConvertedMoji(input: "", kakutei: Romaji.Moji(firstRomaji: ".", kana: "."))
} else {
fatalError()
}
} else if let moji = table[input] {
return ConvertedMoji(input: moji.remain ?? "", kakutei: moji)
} else if undecidedInputs.contains(input) {
return ConvertedMoji(input: input, kakutei: nil)
} else if input.hasPrefix("n") && input.count == 2 {
return ConvertedMoji(input: String(input.dropFirst()), kakutei: Romaji.n)
} else if input.count > 1, let c = input.last {
return convert(String(c))
return convert(String(c), punctuation: punctuation)
}
return ConvertedMoji(input: input, kakutei: nil)
}
Expand Down
10 changes: 10 additions & 0 deletions macSKK/Settings/GeneralView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,16 @@ struct GeneralView: View {
Text("ASDFGHJKL").tag("ASDFGHJKL")
Text("AOEUIDHTN").tag("AOEUIDHTN")
}
Picker("Behavior of Comma", selection: $settingsViewModel.comma) {
ForEach(Punctuation.Comma.allCases, id: \.id) { comma in
Text(comma.description).tag(comma)
}
}
Picker("Behavior of Period", selection: $settingsViewModel.period) {
ForEach(Punctuation.Period.allCases, id: \.id) { period in
Text(period.description).tag(period)
}
}
Section {
Picker("Number of inline candidates", selection: $settingsViewModel.inlineCandidateCount) {
ForEach(0..<10) { count in
Expand Down
14 changes: 14 additions & 0 deletions macSKK/Settings/SettingsViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,8 @@ final class SettingsViewModel: ObservableObject {
@Published var enterNewLine: Bool
@Published var systemDict: SystemDict.Kind
@Published var selectingBackspace: SelectingBackspace
@Published var period: Punctuation.Period
@Published var comma: Punctuation.Comma

// 辞書ディレクトリ
let dictionariesDirectoryUrl: URL
Expand Down Expand Up @@ -284,9 +286,12 @@ final class SettingsViewModel: ObservableObject {
selectCandidateKeys = UserDefaults.standard.string(forKey: UserDefaultsKeys.selectCandidateKeys)!
enterNewLine = UserDefaults.standard.bool(forKey: UserDefaultsKeys.enterNewLine)
selectingBackspace = SelectingBackspace(rawValue: UserDefaults.standard.integer(forKey: UserDefaultsKeys.selectingBackspace)) ?? SelectingBackspace.default
comma = Punctuation.Comma(rawValue: UserDefaults.standard.integer(forKey: UserDefaultsKeys.punctuation)) ?? .default
period = Punctuation.Period(rawValue: UserDefaults.standard.integer(forKey: UserDefaultsKeys.punctuation)) ?? .default
Global.selectCandidateKeys = selectCandidateKeys.lowercased().map { $0 }
Global.systemDict = systemDict
Global.selectingBackspace = selectingBackspace
Global.punctuation = Punctuation(comma: comma, period: period)

// SKK-JISYO.Lのようなファイルの読み込みが遅いのでバックグラウンドで処理
$dictSettings.filter({ !$0.isEmpty }).receive(on: DispatchQueue.global()).sink { dictSettings in
Expand Down Expand Up @@ -461,6 +466,13 @@ final class SettingsViewModel: ObservableObject {
Global.selectingBackspace = selectingBackspace
}.store(in: &cancellables)

$comma.combineLatest($period).dropFirst().sink { (comma, period) in
logger.log("句読点の入力が変更されました。 カンマ: \(comma.description, privacy: .public), ピリオド: \(period.description, privacy: .public)")
let punctuation = Punctuation(comma: comma, period: period)
Global.punctuation = punctuation
UserDefaults.standard.set(punctuation.rawValue, forKey: UserDefaultsKeys.punctuation)
}.store(in: &cancellables)

NotificationCenter.default.publisher(for: notificationNameDictLoad).receive(on: RunLoop.main).sink { [weak self] notification in
if let loadEvent = notification.object as? DictLoadEvent, let self {
if let userDict = Global.dictionary.userDict as? FileDict, userDict.id == loadEvent.id {
Expand Down Expand Up @@ -500,6 +512,8 @@ final class SettingsViewModel: ObservableObject {
enterNewLine = false
systemDict = .daijirin
selectingBackspace = SelectingBackspace.default
comma = Punctuation.default.comma
period = Punctuation.default.period
}

// DictionaryViewのPreviewProvider用
Expand Down
2 changes: 2 additions & 0 deletions macSKK/Settings/UserDefaultsKeys.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,6 @@ struct UserDefaultsKeys {
static let systemDict = "systemDict"
// 変換候補選択中のバックスペースの挙動
static let selectingBackspace = "selectingBackspace"
// カンマ、ピリオド入力時の句読点
static let punctuation = "punctuation"
}
12 changes: 6 additions & 6 deletions macSKK/StateMachine.swift
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,7 @@ final class StateMachine {
switch state.inputMode {
case .hiragana, .katakana, .hankaku:
if input.isAlphabet && !action.optionIsPressed() {
let result = Global.kanaRule.convert(input)
let result = Global.kanaRule.convert(input, punctuation: Global.punctuation)
if let moji = result.kakutei {
if action.shiftIsPressed() {
state.inputMethod = .composing(
Expand All @@ -389,7 +389,7 @@ final class StateMachine {
cursorPosition: action.cursorPosition),
specialState: specialState)
}
let result = Global.kanaRule.convert(characters)
let result = Global.kanaRule.convert(characters, punctuation: Global.punctuation)
if let moji = result.kakutei {
if action.shiftIsPressed() && moji.kana.isHiragana {
state.inputMethod = .composing(
Expand Down Expand Up @@ -631,7 +631,7 @@ final class StateMachine {
if state.inputMode == .direct {
return handleComposingPrintable(
input: ";",
converted: Global.kanaRule.convert(";"),
converted: Global.kanaRule.convert(";", punctuation: Global.punctuation),
action: action,
composing: composing,
specialState: specialState)
Expand Down Expand Up @@ -759,9 +759,9 @@ final class StateMachine {
if let input {
let converted: Romaji.ConvertedMoji
if !input.isAlphabet, let characters = action.characters() {
converted = Global.kanaRule.convert(romaji + characters)
converted = Global.kanaRule.convert(romaji + characters, punctuation: Global.punctuation)
} else {
converted = Global.kanaRule.convert(romaji + input)
converted = Global.kanaRule.convert(romaji + input, punctuation: Global.punctuation)
}

return handleComposingPrintable(
Expand Down Expand Up @@ -915,7 +915,7 @@ final class StateMachine {

@MainActor private func useKanaRuleIfPresent(inputMode: InputMode, romaji: String, input: String) -> Romaji.ConvertedMoji? {
if inputMode != .direct && !romaji.isEmpty {
let converted = Global.kanaRule.convert(romaji + input)
let converted = Global.kanaRule.convert(romaji + input, punctuation: Global.punctuation)
if converted.kakutei != nil && converted.input == "" {
return converted
} else {
Expand Down
4 changes: 4 additions & 0 deletions macSKK/en.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@
"Copy" = "Copy";
"Number of inline candidates" = "Number of inline candidates";
"Backspace in selecting candidates" = "Backspace in selecting candidates";
"Behavior of Comma" = "Behavior of Comma";
"Behavior of Period" = "Behavior of Period";
"Candidates font size" = "Candidates font size";
"Annotation font size" = "Annotation font size";
"Find completion from all dictionaries" = "Find completion from all dictionaries";
Expand Down Expand Up @@ -122,3 +124,5 @@
"SelectingBackspaceCancel" = "Go back one step";
"SelectingBackspaceDropLastInlineOnly" = "Delete a last character & commit in Inline";
"SelectingBackspaceDropLastAlways" = "Delete a last character & commit always";
"Follow Romaji-Kana Rule" = "Follow Romaji-Kana Rule";
"EnterKey" = "Enter \"%@\"";
4 changes: 4 additions & 0 deletions macSKK/ja.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@
"Copy" = "コピー";
"Number of inline candidates" = "インラインで表示する変換候補の数";
"Backspace in selecting candidates" = "変換候補選択中のバックスペース";
"Behavior of Comma" = "カンマの挙動";
"Behavior of Period" = "ピリオドの挙動";
"Candidates font size" = "変換候補のフォントサイズ";
"Annotation font size" = "注釈のフォントサイズ";
"Find completion from all dictionaries" = "ユーザー辞書だけでなくすべての辞書から補完を探す";
Expand Down Expand Up @@ -122,3 +124,5 @@
"SelectingBackspaceCancel" = "一つ前の状態に戻す";
"SelectingBackspaceDropLastInlineOnly" = "インライン時は一文字削除して確定";
"SelectingBackspaceDropLastAlways" = "常に一文字削除して確定";
"Follow Romaji-Kana Rule" = "ローマ字かな変換ルールに従う";
"EnterKey" = "\"%@\" を入力";
1 change: 1 addition & 0 deletions macSKK/macSKKApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ struct macSKKApp: App {
UserDefaultsKeys.enterNewLine: false,
UserDefaultsKeys.systemDict: SystemDict.Kind.daijirin.rawValue,
UserDefaultsKeys.selectingBackspace: SelectingBackspace.default.rawValue,
UserDefaultsKeys.punctuation: Punctuation.default.rawValue
])
}

Expand Down
20 changes: 20 additions & 0 deletions macSKKTests/PunctuationTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// SPDX-License-Identifier: GPL-3.0-or-later

import XCTest

@testable import macSKK

final class PunctuationTests: XCTestCase {
func testInit() {
guard var punctuation = Punctuation(rawValue: 0) else { XCTFail(); return } // default, default
XCTAssertEqual(punctuation.comma, .default)
XCTAssertEqual(punctuation.period, .default)
punctuation = Punctuation(comma: .comma, period: .maru)
XCTAssertEqual(punctuation.comma, .comma)
XCTAssertEqual(punctuation.period, .maru)
XCTAssertEqual(punctuation.rawValue, 256 | 2)
let punctuation2 = Punctuation(rawValue: punctuation.rawValue)
XCTAssertEqual(punctuation2?.comma, .comma)
XCTAssertEqual(punctuation2?.period, .maru)
}
}
Loading