Skip to content

feat(ui): status bar icon reflects ascii_mode#1122

Open
metalbreeze wants to merge 6 commits into
rime:masterfrom
metalbreeze:feat/ascii-mode-status-icon
Open

feat(ui): status bar icon reflects ascii_mode#1122
metalbreeze wants to merge 6 commits into
rime:masterfrom
metalbreeze:feat/ascii-mode-status-icon

Conversation

@metalbreeze
Copy link
Copy Markdown

@metalbreeze metalbreeze commented Apr 20, 2026

Summary

  • Add an NSStatusItem that shows when Squirrel is in Chinese mode and A when ascii_mode is on, driven by the Rime option-change notification.
  • Auto-hide the status item when the active input source is not Squirrel, using a kTISNotifySelectedKeyboardInputSourceChanged observer.
  • Refactor the option branch of the Rime notification handler so optionName can be extracted and fed to the status-icon update, preserving existing schema/option paths.
  • Small helper SquirrelInstaller.currentInputSourceID() added for the visibility check.

Notes for reviewer

  • No changes to SquirrelInputController, its IMK right-click menu, Info.plist, or input source enablement logic.
  • No UI changes when Squirrel is not the active input source (status item is hidden).
  • The status item has no click menu; it is purely a mode indicator.

Test plan

  • Build Release succeeds (make release)
  • After install, menu bar shows while Squirrel is active in Chinese mode
  • Pressing Shift toggles the icon to A while Squirrel is active
  • Switching to ABC (or any non-Squirrel source) hides the icon
  • Right-click on Squirrel's own menu-bar icon still shows Deploy / Sync / Settings / etc.

Generated with Claude Code

Add an NSStatusItem that shows "中" when Squirrel is in Chinese input
mode and "A" when ascii_mode is toggled on (e.g. via Shift). The icon
auto-hides when the active input source is not Squirrel, driven by a
kTISNotifySelectedKeyboardInputSourceChanged observer.

The Rime notification handler is refactored to extract optionName so
the ascii_mode toggle can drive the status icon update, without
disturbing the existing schema / option notification paths.

No changes to IMKInputController, its right-click menu, or system
input source enablement.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@metalbreeze
Copy link
Copy Markdown
Author

image image image

@LEOYoon-Tsaw
Copy link
Copy Markdown
Member

How to turn it off if user doesn't want an extra icon?

@lotem
Copy link
Copy Markdown
Member

lotem commented Apr 21, 2026

有人說能用狀態圖標替換輸入法圖標,有這種 API 嗎?

https://github.com/orgs/rime/discussions/1214#discussioncomment-16610551


func applyStatusIcon(asciiMode: Bool) {
guard let button = statusItem?.button else { return }
button.title = asciiMode ? "A" : "中"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We can use get_state_label_abbreviated to display the status label defined in the input schema.

delegate.updateStatusIcon(asciiMode: state)
}
// off
if !delegate.enableNotifications {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

} else if delegate.enableNotifications {
   // 顯示狀態消息框
}

}

// off
if !delegate.enableNotifications {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

if delegate.enableNotifications {
  // 顯示狀態消息框
}

optionName = nil
}
if optionName == "ascii_mode" {
delegate.updateStatusIcon(asciiMode: state)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

在此測試狀態圖標開關選項。

若顯示狀態圖標,則無須顯示消息框,對吧?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

我觉得还是根据需要显示,不需要做成互斥的。
希望两个地方都可以有显示。

Add a new top-level boolean key in squirrel.yaml (default true) so users
can hide the 中/A menu-bar icon with a custom patch:

  patch:
    show_status_icon: false

Re-reads the value in loadSettings() and creates / removes the
NSStatusItem via refreshStatusItem(), so "Squirrel --reload" picks up
the toggle without relaunching.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Copy link
Copy Markdown
Author

@metalbreeze metalbreeze left a comment

Choose a reason for hiding this comment

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

我觉得还是根据需要显示,不需要做成互斥的。
我希望两个地方都可以有显示。

shu.nie and others added 3 commits April 21, 2026 23:43
Previously the ascii_mode menu-bar icon hardcoded "A" / "中", ignoring
each schema's own states: declaration (e.g. luna_pinyin_simp defines
[中文, 西文]). This commit:

1. Calls get_state_label_abbreviated in the option-notification path and
   reuses the short label for the icon, so the icon respects the active
   schema's convention by default.
2. Adds two optional yaml keys, status_icon/ascii and status_icon/chinese,
   that let users pin compact single-character glyphs when the schema's
   label is too wide for the menu bar.

Resolution order for the button title: user override -> schema short label
-> hardcoded "A"/"中" fallback. Restructures the option-notification
handler so the label fetch is shared between the icon and the status
bubble -- the bubble remains generic (fires for any option when
enableNotifications is on), while the icon is still gated to ascii_mode.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Before, the three status-icon settings had inconsistent styles:
  show_status_icon: true       (flat, underscored)
  status_icon/ascii: A         (subtree, slashed)
  status_icon/chinese: 中       (subtree, slashed)

Unify under one status_icon/ subtree, matching Rime's convention for
grouped settings (ascii_composer/switch_key, key_binder/bindings, ...):

  status_icon:
    show: true
    ascii: A
    chinese: 中

show_status_icon was only introduced in the previous commit on this
feature branch (3dad524) and has not been released, so the rename is a
pure pre-merge cleanup with no user migration needed outside this PR.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
get_state_label_abbreviated returns a RimeStringSlice whose .str points
to a null-terminated C string but whose .length may be shorter — for
abbreviated=true without an explicit `abbrev:` field, librime clips
.length to the first Unicode character (see switches.cc
first_unicode_byte_length).

The Swift side was using String(cString: slice.str), which ignores
.length and reads to the null terminator. As a result:
  - The "short" label for ascii_mode on luna_pinyin_simp
    (states: [中文, 西文]) came through as "中文" / "西文" instead of
    the intended "中" / "西".
  - The menu-bar icon, which defaults to this short label when no
    user override is set, showed "中文" / "西文" taking up far more
    menu-bar space than a status glyph should.

Add a private RimeStringSlice.asString that constructs a Swift String
from Data(bytes:count:) using the slice's own length, and switch both
notificationHandler conversions (long + short) to use it. The long path
is unchanged in behavior (long always has full length) but now goes
through the same helper for consistency.

After this fix the icon, with default config on luna_pinyin_simp, will
correctly show "中" / "西" — no user override needed.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@lotem
Copy link
Copy Markdown
Member

lotem commented Apr 22, 2026

很抱歉,我以爲 get_state_label_abbreviated 能直接從方案裏得到「中」「A」,當時這個 API 是設計爲這樣用的,但需要在方案中設定好,如這份測試方案
https://github.com/rime/librime/blob/master/data/minimal/luna_pinyin.schema.yaml#L22

我驚覺主要的方案都還沒有把 ascii_mode 的文字更新爲「ABC」,因此目前無法取得預想效果。

理想中,方案設定的短標籤應優先於全局配置,比如爲少數民族語文設計的輸入方案,就應當能換掉「中」字。
但是出於上述「ABC」未能普遍應用到方案的原因,只能先放棄由方案提供狀態標籤的功能。

現在這麼複雜的代碼無法發揮作用。麻煩你改回在代碼裏寫定「中」「A」(要不要寫成全角的 避免寬度變化?),不必支持這兩個字符串配置。僅保留狀態欄圖標開關。

以後可能要先在方案中普及「ABC」標籤,再切換到 get_state_label_abbreviated API。

The reviewer asked to drop the schema-label complexity in favour of
hardcoded glyphs, since mainstream schemas don't yet declare `abbrev:`
for ascii_mode and so `get_state_label_abbreviated` returns wide labels
like "中文" / "西文" that are unsuitable for a menu-bar glyph.

Take a middle path that satisfies the simplification request without
giving up forward compatibility:

- Drop the user-facing `status_icon/ascii` and `status_icon/chinese`
  config keys (and the cached instance properties that backed them).
- Drop the `RimeStringSlice.asString` length-aware helper from the
  prior commit. `String(cString:)` reads `.str` to its null terminator,
  which gives the correct abbrev for schemas that declare it (the
  reviewer's referenced `librime/data/minimal/luna_pinyin.schema.yaml`
  has `abbrev: [中, A]` -> `.str` is "中\0" -> reads "中") and the full
  `states:` value otherwise. No client-side slicing necessary.
- Hardcode the fallback at full-width "中" / "A" (per reviewer
  suggestion) for schemas that don't define `states:` at all.
- Keep the `status_icon/show` subtree key untouched.

Net effect: schemas that declare `abbrev: [中, A]` get compact glyphs
for free; schemas that don't see their `states:` value as-is and can
opt into compactness by adding `abbrev:` themselves; the codebase no
longer carries the per-state config knobs the reviewer rejected.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@metalbreeze
Copy link
Copy Markdown
Author

感謝仔細評審。已按你的建議簡化:

  • 刪掉 status_icon/ascii / status_icon/chinese 這兩個用戶配置項。
  • 硬編碼保底字符改用全角 / ,按你的建議保持菜單欄寬度穩定。

有一處細節想聽聽你的意見:注意到你引用的 librime/data/minimal/luna_pinyin.schema.yaml 實際上已經聲明了 abbrev: [中, A],而 Swift 的 String(cString:)RimeStringSlice.str 時,只要方案聲明了 abbrev,讀出來的恰好就是那個 abbrev 字符串(即 switches.cc:151 處的 value->str().c_str())。

所以我保留了「讀取方案 short state label」這條通路,但沒在客戶端做 .length 切片——聲明了 abbrev: 的方案直接得到緊湊標籤,沒聲明的方案就原樣顯示 states: 的值,硬編碼的 / 僅在方案完全沒定義 states: 時保底。

這樣代碼比之前簡單很多,方案以後逐步添加 abbrev: 也能自動生效,不需要讓 Squirrel 重新發版。當然,如果你認爲應該完全跳過方案、永遠硬編碼,我也可以再刪一輪——你說一聲就行。

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants