@@ -20,6 +20,10 @@ private let appsWithoutDummyPreedit: Set<String> = [
2020 " com.alibaba.DingTalkMac " ,
2121]
2222
23+ private func isJetBrains( _ app: String ) -> Bool {
24+ return app == " com.google.android.studio " || app. starts ( with: " com.jetbrains. " )
25+ }
26+
2327private var controller : IMKInputController ? = nil
2428
2529public func setController( _ ctrl: Any ) {
@@ -77,24 +81,29 @@ public func commitAndSetPreeditSync(
7781 if !commit. isEmpty {
7882 commitString ( client, commit)
7983 }
84+ let app = client. bundleIdentifier ( ) ?? " "
8085 // Without client preedit, Backspace bypasses IM in Terminal, every key is both
81- // processed by IM and passed to client in iTerm and VSCode terminal, Backspace
82- // is double-processed in Chrome address bar/VSCode editor/Bruno URL input, ArrowDown
83- // is swallowed in Spotlight, so we force a dummy client preedit here.
86+ // processed by IM and passed to client in iTerm, JetBrains and VSCode terminal,
87+ // Backspace is double-processed in Chrome address bar/VSCode editor/Bruno URL input,
88+ // ArrowDown is swallowed in Spotlight, so we force a dummy client preedit here.
8489 // Some apps also need it to get accurate caret position to place candidate window.
8590 // This is fine even when there is selected text. In Word, not using dummy preedit to
8691 // replace selected text will let Esc bypass IM. When using Shift+click to select, if
8792 // interval is too little, IM switch happens, but dummyPreedit is false in that case.
8893 if preedit. isEmpty && dummyPreedit {
89- if appsWithoutDummyPreedit. contains ( client . bundleIdentifier ( ) ?? " " ) {
94+ if appsWithoutDummyPreedit. contains ( app ) {
9095 return
9196 }
9297 let length = client. length ( )
9398 let selectedRange = client. selectedRange ( )
99+ // We prefer ZWS to avoid text layout shift after caret, e.g. VSCode.
94100 // For SwiftUI TextField, there is a bug that if caret is at the end of text, zero-width space preedit
95101 // spreads from the start to the end, making the whole text underlined. Fortunately, SwiftUI's length
96102 // and selectedRange are reliable, so we use a normal space in this case.
97- if length > 0 && length - currentPreedit. count == NSMaxRange ( selectedRange) {
103+ // JetBrains-based IDEs displays zero-width space as "ZWSP" so we'd rather use a normal space.
104+ if ( length > 0 && length - currentPreedit. count == NSMaxRange ( selectedRange) )
105+ || isJetBrains ( app)
106+ {
98107 setPreedit ( client, " " , 0 )
99108 } else {
100109 setPreedit ( client, zeroWidthSpace, 0 )
0 commit comments