Skip to content

Bundled Bangla fonts, macOS-style icons, native layout tab, Chromium cursor fixes, and build cleanups - #14

Open
Zibonnn wants to merge 16 commits into
ARahim3:mainfrom
Zibonnn:main
Open

Zibonnn wants to merge 16 commits into
ARahim3:mainfrom
Zibonnn:main

Conversation

@Zibonnn

@Zibonnn Zibonnn commented Sep 17, 2026

Copy link
Copy Markdown

Summary

Design-driven changes to how Lekho looks and renders Bangla, plus correctness and size fixes that fell out along the way. 13 commits ahead of main, no divergence.

Icons (design)

  • New app icon in the macOS style: rounded squircle, layered depth, sized for Dock and Finder at every slot.
  • New menu-bar icon drawn to match the native "EN" input source glyph, so switching between English and Lekho looks like one system. It inverts correctly on dark menu bars.

Fonts and rendering (design)

  • Bundled July and BCC Purno under fonts/, shipped in the app via ATSApplicationFontsPath, so the candidate panel and welcome window render Bangla in July regardless of what the user has installed. Both are open-source fonts released by the Government of Bangladesh.
  • Installed system-wide on launch. A background task copies the bundled fonts into ~/Library/Fonts so every app can use them. An existing copy is replaced only when the bundled one is newer; /Library/Fonts is never touched. The uninstaller offers to remove them.
  • NSFont.withBangla(_:) builds one font whose cascade falls through to July (July-Bold for semibold and up) for Bengali. Latin, digits and emoji keep the system font, so mixed candidates line up.

Welcome window (design)

  • Native Avro layout tab. LayoutWebView and the WebKit dependency are gone. The layout is ~70 AppKit cards grouped by section with a live search field.
  • Vowel cards show the vowel sign (আ / া, ই / ি) instead of a ক-based example.
  • Phala and reph cards show their marks. A zero-width joiner next to the hasanta makes the shaper emit the standalone subjoined form, so ব-ফলা, য-ফলা, র-ফলা and রেফ display the real glyph rather than hasanta plus consonant.
  • Special section corrected against the engine. Backtick is a pattern separator (it emits nothing), not ZWJ. Tilde and .. have no Avro rule, so the ZWNJ and nukta cards are dropped.
  • Shortcut table replaces the row-by-row list; shared cardHeader and scrollingPage helpers keep the tabs consistent.
  • Tabs build lazily on first selection.

Input controller

  • Chromium cursor position. Chromium ignores selectionRange.location for a collapsed selection and puts the caret at 0. For Chromium clients we pass {0, N} (caret lands at the end), set markedClauseSegment, and anchor the panel from selectedRange() with a marked-range fallback.
  • Chromium detection by framework bundle instead of a bundle-id substring list. Every Chromium/Electron app ships a <Name> Framework.framework, which catches Arc (company.thebrowser.Browser) and Cursor (com.todesktop.<hash>). Cached per bundle id.
  • Candidates extracted once per keystroke and reused by the panel and candidates(_:), instead of three walks over riti's list.
  • Remembered selection index 0 is treated as "nothing remembered", since riti returns 0 for both cases. Without this, phonetic-first stopped applying once a word had been seen.
  • Ctrl+Backspace reaches riti for whole-word delete instead of being passed through.
  • UInt8(clamping:) on the selected index instead of a trapping conversion.

Candidate panel

  • Clicking the bottom padding strip no longer selects the next, hidden row.

Build, scripts, CI

  • Release binary is stripped (~400 KB smaller).
  • Icon generator renders into an explicit 8-bit rep; tiffRepresentation produced 16-bit slices and a 2.2 MB icns. Now 900 KB.
  • create_dmg.sh reads the version from Info.plist for the DMG name, pkgbuild, and distribution XML.
  • uninstall.sh uses rm -rf on the /Applications entry, which may be a symlink or a real copy.
  • Homebrew bump workflow passes tag values through env: and targets ${{ github.repository_owner }}/homebrew-lekho, which resolves to your tap here.

Notes for review

  • Version bumped to 0.2.7 in Info.plist. Adjust as you like.
  • Not tested on Intel.

🤖 Generated with Claude Code

zibon-exa and others added 16 commits May 24, 2026 13:59
…using grapheme cluster counts and update app icon assets
- Fix Chrome/Chromium cursor appearing to the left of composition text:
  Chromium ignores selectionRange.location when length == 0 (collapsed
  cursor) and always positions the cursor at the start of the composition.
  Workaround: pass selectionRange {0, utf16Length} for Chromium clients so
  the cursor lands at the end of the selection (= end of composition).
  Non-Chromium clients continue using the standard {utf16Length, 0} form.
  Also adds a dedicated Chromium-specific path in getCursorRect that uses
  selectedRange() first (which now correctly reports end-of-composition),
  then falls back to the right edge of the last marked character.

- Add NSMarkedClauseSegment: 0 attribute so Chromium identifies the entire
  composition string as one coherent segment.

- Replace AppIcon.icns with icon built in Icon Composer (Apple).
  New .icns embeds both Default (light) and Dark appearance variants at
  all standard sizes (16–512px × 1x and @2x), giving macOS automatic
  appearance switching in the Dock and Launchpad.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Bundled fonts are registered via ATSApplicationFontsPath; on launch a
background task copies them into ~/Library/Fonts, replacing only older
copies. NSFont.withBangla gives system fonts a July cascade for Bengali,
used by the candidate panel and welcome window. Welcome window tabs now
build lazily and the WebKit layout view is replaced by a native one.
Uninstaller offers to remove the copied fonts.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Extract candidate strings once in resolveSelectedIndex and reuse them for
the panel and IMK candidates(). Treat a remembered index of 0 as "nothing
remembered". Let Ctrl+Backspace reach riti for whole-word delete. Detect
Chromium/Electron clients by the "<Name> Framework.framework" in the
app's Frameworks dir so Arc and Cursor get the cursor workaround.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
DMG script now takes the pkg version from Info.plist too.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Vowel cards show the sign (আ / া) instead of a ক-based example. The
phala and reph cards carry their marks; a ZWJ next to the hasanta makes
the shaper emit the standalone subjoined form in July.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… layout grid

- Candidate panel uses NSGlassEffectView on macOS 26+ with a custom elevated
  shadow; the flat panel remains as the pre-26 fallback
- Numbers and words are vertically centered; selected row has more padding and
  an Enter symbol; larger fonts
- Candidates found in the bundled dictionary get a checkmark; the word list
  preloads at launch off the main thread
- Getting started header icon is centered against its title and subtitle
- Avro Layout grid: 2x Bangla glyphs, 1.5x key labels, wider vowel separators

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@ARahim3

ARahim3 commented Sep 22, 2026

Copy link
Copy Markdown
Owner

Hi @Zibonnn, that's a lot of careful work, and I read all of it. Thank you.

I can't take it as one PR though. It changes icons, fonts, the layout tab, the input controller and the build scripts together, and the input controller was rewritten for v0.3.0 in the meantime, so it no longer applies. For the design side (icons, bundled fonts, the native layout tab) I'd like to talk before any code, one topic per issue.

Several bugs you caught are fixed in v0.3.0, and you're credited in the release notes: the remembered-selection 0 problem that broke Phonetic-first, the trapping UInt8 conversion, whole-word delete (Option+Backspace), and the click below the last row of the panel.

The Chromium caret one I'd like to look at properly. Could you open an issue with the app and steps to reproduce?

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

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants