Skip to content

fix: 「/ キーで中黒」の優先と、SigilWord の状態リセット漏れによる全角入力ロックの解消 - #857

Open
Mithril-3d wants to merge 6 commits into
yksr-melt:mainfrom
Mithril-3d:fix/slash-middle-dot-and-sigil-reset
Open

Mithril-3d wants to merge 6 commits into
yksr-melt:mainfrom
Mithril-3d:fix/slash-middle-dot-and-sigil-reset

Conversation

@Mithril-3d

@Mithril-3d Mithril-3d commented Oct 18, 2026 •

Copy link
Copy Markdown

変更の内容

Fixes #638

設定で「/ キーで中黒「・」」を有効にしている場合でも、行頭や日本語入力時に中黒が入力できない問題、およびその後に半角英数が素通しされ続けて全角日本語が打てなくなる不具合を修正しました。

  • 優先順位の調整: 行頭や空白直後の / が、SlashAsMiddleDot 設定よりも先に AI コマンド記号(Sigil)のパススルー判定に横取りされていたため、日本語入力時は SlashAsMiddleDot を優先して中黒(・)を変換ボックスに入れるよう修正しました。
  • SigilWord 状態のリセット処理: Sigil 入力判定後に Backspace で文字が消去された場合やキャレットが移動した際に、残存していた状態(_sawBefore 等)を適切にリセットし、以降のキー入力がコマンドの続きと誤認されて半角ロックが発生するのを防ぎました。
  • POSIX パス誤判定の防止: ProtectedSpan.TryPosixPath において、先頭のスラッシュのみで通常入力が POSIX パスとして誤保護されないよう判定を調整しました。
  • テストの追加: 中黒入力、Sigil パススルー解除、POSIX パス誤判定防止の回帰テストを SessionFacadeTests 等に追加しました。

確かめること

  • kyouhagoogledekensaku → 今日はgoogleで検索
  • wsldeshell → wslでshell

確認したこと

  • dotnet run --project src/Meltype.Core.Tests のテストが通る (Windows なら src/Meltype.Tests)
  • 判定・変換を変えたときは、報告された例をテストに足した
  • 辞書だけの変更
  • 実際に打って確かめた (OS とアプリ: Windows 11 / Antigravity IDE, VSCode)
  • AI を使った (使った部分: コードの実装・テストコードの下書き) — 中身を理解し、自分で確かめた。

貢献者ライセンス同意 (CLA)

bot のコメントに対し、すでに「CLA に同意します」とコメント済みです(同意確認済み)。

…ret/mode change

- Prioritize SlashAsMiddleDot over sigil pass-through when typing '/' at the beginning of composition or after kana/punctuation.
- Reset SigilWord state and boundary tracking when characters are deleted via Backspace, caret moves, or mode switches.
- Prevent Japanese input with leading '/' from being wrongly protected as a POSIX path in ProtectedSpan.
- Add regression tests covering middle dot insertion, sigil pass-through recovery, and POSIX path protection.
@github-actions github-actions Bot added the pr Pull Request label Oct 18, 2026
@github-actions

github-actions Bot commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor

@Mithril-3d さん、Pull Request ありがとうございます!

Meltype は GNU GPL v3 で公開していますが、GPL v3 の条件で使えない方には作者が個別に利用を認めることがあります。これを続けられるように、初めての方には次の貢献者ライセンス同意 (CLA) をお願いしています (詳しく)。

私は、この Pull Request で提供する貢献 (コード・辞書・文書など) について、次のことに同意します。

  1. 貢献は私自身が作成したもので、私にはそれを提供する権利がある。
  2. 私は Meltype の作者に対し、貢献を複製・改変・配布・サブライセンスする、無償で取り消し不能な、世界的・非独占的な権利を許諾する。
    これには、GNU GPL v3 以外の条件 (作者が個別に認める利用を含む) で配布することを含む。
  3. 貢献の著作権は私に残り、私は自分の貢献を自由に利用できる。

同意していただける場合は、この Pull Request に次の 1 行だけをコメントしてください (一度同意すれば、次の Pull Request からは不要です)。

CLA に同意します

英語なら I agree to the CLA でも大丈夫です。


✅ @Mithril-3d さん、CLA への同意ありがとうございます。記録しました (コメント)。次の Pull Request からは不要です。

@Mithril-3d

Copy link
Copy Markdown
Author

CLA に同意します

github-actions Bot added a commit that referenced this pull request Oct 18, 2026

@yksr-melt yksr-melt left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

レビューしました。SigilWord の状態がアプリ側で消された/キャレットが動いたときに戻らず全角入力がロックされる問題を、CaretMoved (passedVk=0 / クリック / フォーカス) と before の再確認で解除する方針は良いと思います。気になった点:

  1. ProtectedSpan: 1 階層のパスが保護されなくなる
    / の後ろが英字と - だけなら PosixPath にしない変更で /nihongo は日本語になりますが、/home・/tmp・/etc・/usr のような 1 階層の実在パスも保護対象から外れ、ローマ字としてかなになりそうです (/home → /ほめ)。辞書でローマ字として読める語だけ外す、または英単語判定 (IsDefinitelyEnglish) と組み合わせるなどの方が回帰が少ないと思います。テストも /home などのケースがあると安心です。
  2. SigilWord.PassesThrough の before.Length >= 20
    記号が見つからなくても before が 20 文字以上なら名前の途中とみなす条件の意図 (before が切り詰められている場合?) がコメントから読み取れないので、理由を書くか定数に名前を付けてもらえると助かります。
  3. Windows (MeltypeEngine) と MeltypeSession で条件が違う
    MeltypeSession 側は settings.InputStyle != InputStyle.Kana を見ていますが、MeltypeEngine.StartsComposition 側の新しい条件にはありません。手前でかな入力を除外済みならコメントで、そうでなければ同じ条件に揃えた方が良さそうです。
  4. CompositionController の _modeByKey = true; 追加は他の変更との関係が diff だけでは分からないので、何を直すためか PR 説明かコメントに一言あると助かります。

Generated by Claude Code

@Mithril-3d

Mithril-3d commented Oct 20, 2026 •

Copy link
Copy Markdown
Author

レビューいただきありがとうございます。
ご指摘いただいた点、および追加で判明した中黒モード時のパス保護連携の不具合について、以下の通り修正コミットを追加・プッシュしました。

変更の内容

  1. ProtectedSpan: 1 階層のパス保護改善 (ProtectedSpan.cs, ProtectionTests.cs)
    • POSIX / macOS の実在する代表的なルートディレクトリ群 (CommonRootDirectories) を定義し、確実に保護対象となるようにしました。
      Linux の標準 FHS (bin, boot, dev, etc, home, lib, opt, proc, root, run, sbin, srv, sys, tmp, usr, var 等) および macOS (Users, Applications, Library, System, Volumes, private, cores, Network 等) を網羅しています。
    // POSIX / macOS の代表的なルートディレクトリ名。1 階層の /home や /tmp などは保護対象にする。
    private static readonly HashSet<string> CommonRootDirectories = new(StringComparer.OrdinalIgnoreCase)
    {
        "bin", "boot", "dev", "etc", "home", "lib", "lib64", "media", "mnt", "opt",
        "proc", "root", "run", "sbin", "srv", "sys", "tmp", "usr", "var",
        "Users", "Applications", "Library", "System", "Volumes", "private", "Network", "cores", "data"
    };
  • ご提案いただいた IsDefinitelyEnglish との組み合わせも検討いたしましたが、パス名には usr, var, etc, mnt などの辞書に載らない略語が多いことや、home(ほめ)のような英単語とローマ字が重なる語の境界判断を避けるため、今回は実在する標準ルートディレクトリをホワイトリストで確実に保護する方針といたしました。
  • 当初検討したローマ字判定による未知の語の推測は、/Linux や /Mac などの一般的な英単語まで誤ってパスとして保護され、中黒入力などが阻害される副作用を生むため削除し、実在する標準ルートディレクトリのホワイトリストに絞って保護するようにしています。
  1. CompositionText.ProtectedSpans: 中黒モード(SlashAsMiddleDot)時のルートパス保護の連携修正 (CompositionText.cs, ProtectionTests.cs)
    • 問題の原因:
      従来のコードでは、打ち始めに / を入力して中黒(・)になった場合、CompositionText.ProtectedSpans 内で
      slash ? ProtectedSpanScanner.Scan(raw[1..])
      のように先頭の / を切り落としてスキャンしていました。
      このため、「/ キーで中黒」が ON の環境では、後ろに home と入力して原文が /home になっても、先頭の / が除外されて home 単体でスキャンされてしまい、CommonRootDirectories の /home と照合されず「・ほめ」に化けてしまう不具合が発生していました。
    • 修正内容:
      打ち始めの / が ・ になった場合でも、入力された原文全体(先頭から)が代表的ルートディレクトリや複数階層パス(/home, /tmp, /a/b など)として正当に保護される場合は、先頭の / を切り落とさずにパスとして保護区間に含めるよう修正しました。
        // 打ち始めの / を ・ にしたときでも、原文全体 (先頭から) が代表的なルートディレクトリや複数階層パス (/home, /tmp, /a/b など)
        // として正当に保護される場合は、パスとして保護する。
        var slash = _units is [{ Kana: "・", Raw: "/" }, ..];
        var key = slash ? "・" + raw : raw;
        if (_protectedCache is not null && _protectedCacheRaw == key) return _protectedCache;
        if (slash)
        {
            var fullSpans = ProtectedSpanScanner.Scan(raw);
            if (fullSpans.Count > 0 && fullSpans[0].Start == 0 && fullSpans[0].Kind is ProtectedKind.PosixPath or ProtectedKind.Url)
            {
                _protectedCache = fullSpans;
            }
            else
            {
                _protectedCache = ProtectedSpanScanner.Scan(raw[1..]).Select(s => s with { Start = s.Start + 1 }).ToList();
            }
        }
        else
        {
            _protectedCache = ProtectedSpanScanner.Scan(raw);
        }
        _protectedCacheRaw = key;
        return _protectedCache;
  1. SigilWord.PassesThrough: 20 文字判定の定数化と意図明記 (SigilWord.cs)
    • ホストから渡される before が一定長で切り詰められて先頭記号が押し出された場合の判定であることを明示するため、定数 TruncatedBeforeThreshold = 20 として切り出し、以下の通りコメントを追記しました。
    /// <summary>
    /// ホスト (TSF やエディタ) が直前の文脈 (before) を渡す際、一定文字数 (例: 16〜32 文字) で切り詰めることがある。
    /// 長い名前を入力中に先頭の記号 (/・$・@) が切り詰め境界より手前に押し出された場合でも、
    /// 切り詰められたバッファ全体が名前文字で満たされていれば名前の途中とみなすための閾値。
    /// </summary>
    private const int TruncatedBeforeThreshold = 20;

    // ... (PassesThrough 内の判定処理)
    // 記号で始まっているか、あるいは before が切り詰められて記号が枠外に押し出された (バッファ全体が名前文字) かを判定する
    if (!IsNameChar(before[^1]) || !(IsSigil(before[i]) || (i == 0 && before.Length >= TruncatedBeforeThreshold)))
  1. MeltypeEngine と MeltypeSession の条件の統一 (MeltypeEngine.cs)
    • MeltypeEngine 側の除外条件にも settings.InputStyle != InputStyle.Kana を追加し、MeltypeSession と同じ判定条件に揃えました。
        if (!reconvert && settings.SigilWordsDirect && (_keyboardDirect || settings.InputStyle != InputStyle.Kana) &&
            KeyText.CharFromKey(e.Vk, e.Scan, false) is { } typed &&
            !(typed == '/' && !_keyboardDirect && settings.SlashAsMiddleDot && settings.InputStyle != InputStyle.Kana && !_sigil.IsActive) &&
            _sigil.PassesThrough(typed, _line.Text))
  1. CompositionController の _modeByKey = true; の意図明記 (CompositionController.cs)
    • 半角/全角キーで変換ボックス内の文字種を切り替えた際、F6〜F10 キーと同様に「次の打鍵で見えている文字列を確定して新しい入力を始める」ためのフラグ設定である旨をコード内に明記しました。
        if (VirtualKeys.IsHankakuZenkaku(vk))
        {
            SetMode(_text.IsAlphanumeric ? DisplayMode.Hiragana : DisplayMode.HalfWidthAlphanumeric);
            // 半角/全角キーで変換ボックスの文字種を切り替えたあと、F6〜F10 と同様に次の打鍵で確定して新しい入力を始める。
            _modeByKey = true;
            return;
        }

確かめること

「/ キーで中黒」が OFF の場合:

  • /home → /home
  • /tmp → /tmp
  • /etc → /etc
  • /usr → /usr
  • /nihongo → /日本語
  • kyouha,/ashita → 今日は、/明日

「/ キーで中黒」が ON の場合:

  • /home → /home (中黒で始まってもルートパスとして保護される)
  • /tmp → /tmp
  • /Linux → ・Linux (誤ってパス保護されず、中黒として入力できる)
  • /nihongo → ・日本語

確認したこと

  • 判定・変換を変えたときは、報告された例をテストに足した (/home, /tmp, /data の保護、/Linux の非保護、および中黒 ON 時の /home 保護テストを追加)
  • 辞書だけの変更
  • 実際に打って確かめた (OS とアプリ: Windows 11, Antigravity IDE / VS Code)
  • AI を使った (使った部分: レビュー指摘への対応コード作成・テスト追加・コメント整理) — 中身を理解し、自分で確かめた。

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr Pull Request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[不具合] 中黒(・)が打てない

2 participants