-
Notifications
You must be signed in to change notification settings - Fork 163
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
IVSの異体字セレクタに対応する #1937
IVSの異体字セレクタに対応する #1937
Conversation
単語単位の選択で、IVSも一緒に選択するようにしないとカーソル移動が変な動作になりませんか? |
❌ Build sakura 1.0.4322 failed (commit 93d09eebfe by @berryzplus) |
そこの処理は単語検索とかで使う文字種判別のためのものです。 現状で、カーソル移動や単語選択に問題はなさそうなです。 |
対応要りそうです。 sakura/sakura_core/parse/CWordParse.cpp Lines 143 to 144 in d083650
|
1754221
to
ed1494f
Compare
❌ Build sakura 1.0.4323 failed (commit 2f8d5ea217 by @berryzplus) |
ed1494f
to
76d80fa
Compare
✅ Build sakura 1.0.4324 completed (commit 456cd17ef6 by @berryzplus) |
e84eeac
to
3d6d3a9
Compare
✅ Build sakura 1.0.4325 completed (commit 2558967852 by @berryzplus) |
✅ Build sakura 1.0.4326 completed (commit 567b1e6446 by @berryzplus) |
IVS付きの字の直後でバックスペースを押すと現在はまるごと消えてしまいますが、VS Codeは正字になります。 他の正しく表示・カーソル移動できるソフトはまるごと消える実装が多いようなのであくまでご参考までに。
ただし👨👩👦👦(UTF-16だとなんと11文字分、32でも7文字分の化け物)のような複合絵文字は
だとバックスペースを押すごとに切りの良いところまで消されます(この絵文字だと家族一人分ずつ減る挙動をします) |
一旦、そういう仕様で実装してます。 このPRの趣旨は「正字 + 異体字セレクタを1字と扱う」なので、後方から削ったときに異体字セレクタだけ消えるのはおかしな挙動に思えます。 また、サクラエディタの内部実装の都合で削除対象文字列は「選択できる」必要があります。 |
GetCharNext/GetCharPrevが「正字 + 異体字セレクタ」を1字と扱うのはおかしい気がしてきました。 |
メモ帳やWord、Chromium系もそういう仕様なのでそれで問題ないと思います。
「書記素クラスタ」(grapheme cluster)という概念があるので改名の参考になればと思います。 https://ufcpp.net/blog/2017/10/graphemesplitter/ 例: 今回は自前実装でいいですが、最終的にはICUを使うことになります。ICUはWindows 10以降に標準付属しています。 https://learn.microsoft.com/ja-jp/windows/win32/intl/international-components-for-unicode--icu- |
3d6d3a9
to
69c0676
Compare
Kudos, SonarCloud Quality Gate passed! 0 Bugs 97.6% Coverage The version of Java (11.0.20) you have used to run this analysis is deprecated and we will stop accepting it soon. Please update to at least Java 17. |
✅ Build sakura 1.0.4327 completed (commit 47d9a2fe04 by @berryzplus) |
@@ -613,7 +613,7 @@ void CEditView::DeleteData( | |||
nNxtPos = GetCaret().GetCaretLayoutPos().GetX() + CLayoutInt(pcLayout->GetLayoutEol().GetLen()>0?1+m_pcEditDoc->m_cLayoutMgr.GetCharSpacing():0); | |||
} | |||
else{ | |||
nNxtIdx = CLogicInt(CNativeW::GetCharNext( pLine, nLineLen, &pLine[nCurIdx] ) - pLine); | |||
nNxtIdx = nCurIdx + CNativeW::GetSizeOfChar( pLine, nLineLen, nCurIdx); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
この行に対して単体テストを実行できないのが気持ち悪いです。
この行は以下の場合に呼ばれます。
- Deleteキー押下時、選択範囲なしの場合に現在位置の1文字を削除する。
変更前:現在位置の1コードポイントを削除。
変更後:現在位置の1字を削除。
アサーションを書けないのにテストを書く意味はありませんが、モヤッとします。
/*! | ||
* 文字列がIVSの異体字セレクタで始まっているか判定する | ||
*/ | ||
inline bool IsVariationSelector(std::wstring_view text) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
VariationSelectorは他にもBMP内のSVS(U+FE0x。CJK互換漢字や一部の絵文字などと併用)があるのでIsIVS
でもいいのかもしれませんね
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
これちょっと迷いました。
IVS(Ideographic Variation Sequence)
漢字の異体字を表すシーケンス
IVSを構成するのは「正字1字と異体字セレクタ1字」。
異体字セレクタはVS17~VS256なので、1つの正字に対し240通りの異体字を定義できます。
VSの番号が17から始まっているのは、VS1~VS16が別用途に使われているからです。
どこで? → SVS(Standardized Variation Sequence)
SVSは漢字以外の異体字を定義するもので、今回の対応とは関係ありません。
単にVariationSelectorと言った場合「VS1~VS16も含まれる」と判断するのが妥当ですが、ロジックが複雑になるので「ま、いっか。」と考えることにしました。指摘されている通り、VS1~VS16はBMPに定義されるコードポイントで、この関数で判定するとやや微妙な感じになります。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IVS・SVSはそれぞれセットに対する呼び方でしたか。失礼しました。
少し長くなりますがIsSSPVariantSelector
(・IsBMPVariantSelector
)あたりでしょうか?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
差分を見た限りでは不可解な点はありませんでした。とにかく入れてみて様子をうかがう方針で いいと思います。
GetCharNext/GetCharPrevが「正字 + 異体字セレクタ」を1字と扱うのはおかしい気がしてきました。
これらの関数には元々同名のWin32 API関数があり、オリジナルと大きく挙動を変えるのは得策でないように思います。
この関数、どういう目的で個別に実装されたかが不思議です…。本件をコミットすれば使用箇所が1つ減りますが、他は残り一か所(対応する半角括弧の検索)しかなく、文字長1以外の結果を無視するコードなので GetSizeOfChar
で事足ります。本 PR とは別件ですが、削除してコード量を減らしたいところです。
} | ||
else if( nCharChars == 1 ){ | ||
ECharKind ret = CK_NULL; | ||
if(const auto nCharChars = CNativeW::GetSizeOfChar(pData, pDataLen, nIdx); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
重箱の隅をつつく話で恐縮なのですが、この if ブロックの表記スタイルはどのような理由で選択されたものでしょうか?
同ファイルのほかのコードとも、普段の berryzplus さんのコードとも違うスタイル(ですよね?)なので不思議に思いました。
修正する必要はありません。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
カバレッジ対策で修正したコードです。
以下のようなコードで3行目が「未実行」と判定されてしまうバグがOpenCppCoverageに存在するようです。
1 | if (condition) {
2 | return 1;
3 | }
else if (nCharChars == 3 && | ||
IsVariationSelector(pData + nIdx + 1)) | ||
{ | ||
ret = CK_ZEN_ETC; // 全角のその他(漢字など) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
他の箇所で参照されていないので、変数を使わず直に値を返してよいと思います。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
これも上記と同様にカバレッジ対策です(193行目の未実行が誤検知される。)
「修正した」とみなされるコードにだけ対処を入れてるので歪に見えるかも知れません。
代入した値は195行目のreturnで利用してます。
特に誰からも意見がないのでマージしてみます。revert 要求があれば対応します。 |
PR対象
カテゴリ
PR の背景
Windows GDI自体はIVSに対応していることが分かったので、
サクラエディタ側の描画単位を変更することでIVSに対応させます。
変更前: 1文字ずつ描画。UTF16のサロゲートペアのみ2ワードを1字として描画。
変更後: 1文字ずつ描画。「正字+異体字セレクタ」は3ワードを1字として描画する仕様を追加。
IVS以外の異体字セレクタについてはPRの対象ではなりません。
仕様・動作説明
過去の「サロゲートペア対応」を参考に、「1文字ずつ描画」の機構を活かしつつIVSに対応できるよう修正します。
一言で説明すると「正字+異体字セレクタ」を1字とみなすように変更します。
CNativeW::GetSizeOfChar
にコードを追加してIVS対応にします。CNativeW::GetCharNext
にコードを追加してIVS対応にします。CNativeW::GetCharPrev
にコードを追加してIVS対応にします。CNativeW::GetSizeOfChar
にコードを追加してIVS対応にします。CTextMetrics::GenerateDxArray
にコードを追加してIVS対応にします。CTextDrawer::DispText
に元々あったサロゲートペアの下位サロゲートのための処理を拡張して、IVSの異体字セレクタに対応させます。PR の影響範囲
この対応で、とりあえず見た目IVS文字列を表示&編集できるようになります。
テスト内容
関連 issue, PR
参考資料
Wikipedia 異体字セレクタ